在Python中,我如何使用subprocess而不是os.system?

时间:2009-01-07 17:24:51

标签: python syntax scripting process

我有一个Python脚本,它调用带有各种参数的可执行程序(在本例中,它是'sqlpubwiz.exe',它是“Microsoft SQL Server数据库发布向导”):

import os

sqlpubwiz = r'"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe"'
server = 'myLocalServer'
database = 'myLocalDatabase'
connection_values = ['server=' + server, 'database=' + database, 'trusted_connection=true']
connection_string = ';'.join(connection_values)
dbms_version = '2000'
sqlscript_filename = 'CreateSchema.sql'

args = [
        sqlpubwiz,
        'script',
        '-C ' + connection_string,
        sqlscript_filename,
        '-schemaonly',
        '-targetserver ' + dbms_version,
        '-f',
]

cmd = ' '.join(args)
os.system(cmd)

这段代码运行正常,但我想养成使用subprocess的习惯,因为它打算取代os.system。但是,经过几次尝试失败后,我似乎无法正常工作。

如果转换为使用子进程代替os.system,上面的代码将如何?

7 个答案:

答案 0 :(得分:5)

import subprocess
p=subprocess.Popen(args, stdout=subprocess.PIPE)
print p.communicate()[0]

它看起来几乎一样。但路径不应该是“无论路径是什么”。因为这给了我一个错误。你想要“带有转义反斜杠的路径”或r'the path而不转义'。

args也应该是['-arg','args']的形式,而不是['arg argsval']。

答案 1 :(得分:4)

从可执行文件的名称中删除引号。在示例的第一行,而不是

sqlpubwiz = r'"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe"'

使用:

sqlpubwiz = r'C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe'

那是因为你不必逃避任何事情,因为不会涉及shell。

然后只使用subprocess.call(args)(不要join args,将它们作为列表传递)

如果您想捕获输出(os.system无法捕获),请按照subprocess文档进行操作:

result = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
print result

答案 2 :(得分:4)

以下是基于Carlos Rendon(以及nosklo)帮助和建议的修订代码:

# import os
import subprocess    

sqlpubwiz = r'C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz.exe'
server = 'myLocalServer'
database = 'myLocalDatabase'
connection_values = ['server=' + server, 'database=' + database, 'trusted_connection=true']
connection_string = ';'.join(connection_values)
dbms_version = '2000'
sqlscript_filename = 'CreateSchema.sql'       

args = [
            sqlpubwiz,
            'script',
            '-C',
            connection_string,
            sqlscript_filename,
            '-schemaonly',
            '-targetserver',
            dbms_version,
            '-f',
    ]   

# cmd = ' '.join(args)
# os.system(cmd)

subprocess.call(args)

(注意:包含空格的原始参数值需要转换为单独的列表项。)

答案 3 :(得分:4)

仅供参考,subprocess有一个list2cmdline()功能,可让您查看Popen将使用的字符串。

您的版本提供:

'"C:\\Program Files\\Microsoft SQL Server\\90\\Tools\\Publishing\\sqlpubwiz.exe" script "-C server=myLocalServer;database=myLocalDatabase;trusted_connection=true" CreateSchema.sql -schemaonly "-targetserver 2000" -f'

"-C server=myLocalServer;database=myLocalDatabase;trusted_connection=true""-targetserver 2000"附近有额外的引号。

格式正确:

args = [
        sqlpubwiz,
        'script',
        '-C', connection_string,
        sqlscript_filename,
        '-schemaonly',
        '-targetserver', dbms_version,
        '-f',
]

给出:

'"C:\\Program Files\\Microsoft SQL Server\\90\\Tools\\Publishing\\sqlpubwiz.exe" script -C server=myLocalServer;database=myLocalDatabase;trusted_connection=true CreateSchema.sql -schemaonly -targetserver 2000 -f'

此外,还有一点,但是将args之类的序列设置为不需要变为元组而不是列表是一个好习惯。

答案 4 :(得分:0)

请记住,os.system使用shell,所以你必须真正传递

shell=True

到Popen构造函数/调用以正确模拟它。当然,你可能并不需要shell,但它确实存在。

答案 5 :(得分:0)

这不是您问题的直接答案,但我认为这可能会有所帮助。

如果您想要对异常处理等返回的内容进行更精细的控制,您还可以查看pexpect。我已经在我调用的进程不一定退出正常状态信号的情况下使用它,或者我想更多地与它进行交互。这是一个非常方便的功能。

答案 6 :(得分:0)

Windows命令将接受正斜杠'/'来代替路径名中的反斜杠,因此您可以使用前者来避免在命令字符串中转义反斜杠。不完全是你的问题的答案,但也许有用的知识。