我有一个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,上面的代码将如何?
答案 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命令将接受正斜杠'/'来代替路径名中的反斜杠,因此您可以使用前者来避免在命令字符串中转义反斜杠。不完全是你的问题的答案,但也许有用的知识。