如何在Python中使用subprocess代替os.system?

3

我有一个 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。然而,在尝试了几次失败之后,我似乎无法使其正常工作。

如果将上述代码转换为使用subprocess而不是os.system,它会是什么样子?

7个回答

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

它看起来几乎一样。 但路径不应为r'"路径"'. 因为那会给我一个错误。 您需要使用“带转义反斜杠的路径”或r'不需要转义的路径'。

另外,args应该采用['-arg','args']的形式,而不是['arg argsval']。


我尝试了,但是出现了以下错误:WindowsError: [Error 3] 系统找不到指定的路径。 - Ray
我认为Popen将args作为序列而不是一个大的空格分隔字符串。尝试只传递'args'而不是'cmd'。 - Jay Conrod
去掉引号后,脚本可以正常执行,但没有创建任何SQL文件。我如何查看exe的控制台输出? - Ray
现在我看到了来自sqlpubwiz exe的错误。它显示:>缺少/错误的参数。
无法识别的命令行参数“-targetserver 2000” 顺便说一句,我正在使用'args'列表而不是'cmd'。不确定为什么sqlpubwiz不喜欢使用subprocess与os.system相比如何传递参数?
- Ray
这就是为什么我在使用 subprocess 时并没有太多运气,而直接使用 os.system。 - Ray
我敢打赌它想要的命令是 ['-targetserver','2000'],而不是带有空格。 - Carlos Rendon

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

使用 subprocess.call(args) 给我返回了与 Carlos Rendon 相同的错误:> 参数数量不正确/缺失。> 无法识别的命令行参数 '-targetserver 2000'。 - Ray
对于 subprocess,args 值是否需要与 os.system 中字符串命令的构建方式有所不同? - Ray

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)

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

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这样不需要可变性的序列改为元组而不是列表是一个好习惯。


0

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

如果您想要更精细的控制来处理异常等返回内容,您也可以查看pexpect。我曾在调用的进程没有正常退出状态信号或者我想要与其进行更多交互的情况下使用过它。这是一个相当方便的函数。


0

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


0
请记住,os.system使用shell,因此您必须确实传递。
shell=True

为了正确地模拟Popen构造函数/调用,您可能实际上并不需要一个shell,但是这里有它。


1
只是回答问题 :) - Ali Afshar
传递 shell=True 被认为是不安全的。请参阅 https://security.openstack.org/guidelines/dg_use-subprocess-securely.html。 - Ross Smith II

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接