我正在尝试将长而复杂的Windows批处理文件转换为Python。
除了微妙的问题之外,事情是有效的,我怀疑它与引用有关,但不能完全弄明白。
在批处理文件中,这样可以正常工作:
Reg.exe add "HKCR\7-Zip.zip\shell\open\command" /ve /t REG_SZ /d "\"C:\Program Files\7-Zip\7zFM.exe\" \"%%1\"" /f
这个Python代码的意思是,但不是,做同样的事情:
import os, subprocess
cmd = r'Reg.exe add "HKCR\7-Zip.zip\shell\open\command" /ve /t REG_SZ /d "\"C:\Program Files\7-Zip\7zFM.exe\" \"%%1\"" /f'
#os.system(cmd)
subprocess.call(cmd, shell=True)
请注意,(原始)字符串cmd
和批处理文件完全相同
os.system()和subprocess.call()都会产生同样的结果 - 没有错误(Reg.exe表示一切正常),但对系统的影响不同。
在我的测试中,批处理文件配置归档器7z以打开.ZIP文件本身(正确的结果)。
Python代码导致7z打开.ZIP所在的文件夹(错误)。
如何让Python执行批处理文件的工作?
答案 0 :(得分:2)
好的,在黑暗中拍摄:
我会删除UserID x4
1 11
2 33
并使用参数列表传递给shell=True
。报价将自动处理:
subprocess
还要检查cmd = ['Reg.exe','add',r'HKCR\7-Zip.zip\shell\open\command','/ve','/t','REG_SZ','/d',r'"C:\Program Files\7-Zip\7zFM.exe" "%1"','/f']
rc = subprocess.call(cmd)
如果你想“自动”处理这样的几个命令,我建议使用shlex.split
,我并不是说它会解决所有问题,但它在报价方面做得很好(保护带引号的参数,带引号嵌套):
subprocess.call
结果:
import shlex
text = r"""Reg.exe add "HKCR\7-Zip.zip\shell\open\command" /ve /t REG_SZ /d "\"C:\Program Files\7-Zip\7zFM.exe\" \"%%1\"" /f"""
print([x.replace("%%","%") for x in shlex.split(text)]) # %% => % in listcomp, add more filters if needed
与原始前缀相同的是:
['Reg.exe', 'add', 'HKCR\\7-Zip.zip\\shell\\open\\command', '/ve', '/t', 'REG_SZ', '/d', '"C:\\Program Files\\7-Zip\\7zFM.exe" "%1"', '/f']
非常接近吧? :)
答案 1 :(得分:1)
Jean-FrançoisFabre的答案很好,可能是最恐怖的答案。
对我来说不幸的是,我没有耐心分析批处理文件以找出可能需要的其他任何过滤器,所以我提出了这个解决方案,无论语法,引用和转义序列如何,它都能正常工作。批处理文件行:
def do(command):
'''Executes command at Windows command line.'''
import os, subprocess, uuid
batchFile = open("temp_" + str(uuid.uuid4()) + ".bat", 'w')
batchFile.write(command)
batchFile.close()
subprocess.call(batchFile.name, shell=True)
os.remove(batchFile.name)
它只需创建一个单行批处理文件然后运行它。蛮力。
它有点慢,因为它每次都有创建,调用和删除单行批处理文件的开销。
这是一个更快的版本,可以使用所有命令行创建一个大批处理文件。无论何时使用defer=False
调用它,它都会执行迄今为止的所有命令:
# thanks to https://stackoverflow.com/questions/279561/what-is-the-python-equivalent-of-static-variables-inside-a-function
def static_vars(**kwargs):
def decorate(func):
for k in kwargs:
setattr(func, k, kwargs[k])
return func
return decorate
@static_vars(batchFile=None)
def do(command, defer=True):
'''Executes command at Windows command line.
Runs immediately, including all previously deferred commands, if defer is not True
'''
import os, subprocess, uuid
if do.batchFile == None:
do.batchFile = open("temp_" + str(uuid.uuid4()) + ".bat", 'w')
do.batchFile.write(command + "\n") # append to file
if not defer:
do.batchFile.close()
subprocess.call(do.batchFile.name, shell=True)
os.remove(do.batchFile.name)
do.batchFile = None