[英]In Python, how I do use subprocess instead of os.system?
我有一个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)
这段代码运行正常,但我想养成使用子进程的习惯,因为它打算替换os.system。 但是,经过几次尝试失败后,我似乎无法正常工作。
如果转换为使用子进程代替os.system,上面的代码将如何?
import subprocess
p=subprocess.Popen(args, stdout=subprocess.PIPE)
print p.communicate()[0]
它看起来几乎一样。 但路径不应该是“无论路径是什么”。 因为这给了我一个错误。 你想要“带有转义反斜杠的路径”或“r'the path而不转义”。
args的形式也应该是['-arg','args']而不是['arg argsval']。
从可执行文件的名称中删除引号。 在您的示例的第一行,而不是
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
无法执行此操作),请按照子 os.system
文档进行操作:
result = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
print result
以下是基于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)
(注意:包含空格的原始参数值需要转换为单独的列表项。)
仅供参考, 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
不需要变为元组而不是列表是一个好习惯。
请记住,os.system使用shell,所以你必须真正通过
shell=True
到Popen构造函数/调用来正确模拟它。 当然,你可能不需要shell,但它确实存在。
这不是你的问题的直接答案,但我认为它可能会有所帮助。
如果您想要更精细地控制异常处理返回的内容等,您还可以查看pexpect 。 我已经在我调用的进程不一定退出正常状态信号的情况下使用它,或者我想更多地与它进行交互。 这是一个非常方便的功能。
Windows命令将接受正斜杠'/'来代替路径名中的反斜杠,因此您可以使用前者来避免在命令字符串中转义反斜杠。 不完全是你的问题的答案,但也许有用的知道。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.