os.system(cmd)和subprocess.call(cmd,shell = True)不执行与CMD.EXE相同的操作

时间:2018-04-01 19:26:13

标签: python windows

我正在尝试将长而复杂的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执行批处理文件的工作?

2 个答案:

答案 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