【问题标题】:Using python to run other programs使用python运行其他程序
【发布时间】:2011-01-19 19:54:18
【问题描述】:

我有一个在命令行上运行良好的命令。它有很多参数,例如cmd --thing foo --stuff bar -a b input output

我想从 python 运行它并等待它完成。当脚本将内容打印到stdoutstderr 时,我希望它立即显示给用户。

什么是正确的模块?

我试过了:


import commands
output = commands.getoutput("cmd --thing foo --stuff bar -a b input output")
print output

这很好用,除了 stdout 直到最后才返回。


import os
os.system("cmd --thing foo --stuff bar -a b input output")

这会在 cmd 实际完成时打印所有输出。


import subprocess
subprocess.call(["cmd", "--thing foo", "--stuff bar", "-a b", "input", "output"])

这并没有以某种方式正确传递参数(我无法找到确切的问题,但cmd 拒绝了我的输入)。如果我将echo 作为第一个参数,它会打印出当我将其直接粘贴到终端时完美运行的命令。


import subprocess
subprocess.call("cmd --thing foo --stuff bar -a b input output")

和上面的完全一样。

【问题讨论】:

    标签: python unix subprocess


    【解决方案1】:

    您必须单独引用每个字段,即。将选项与其参数分开。

    import subprocess
    output = subprocess.call(["cmd", "--thing", "foo", "--stuff", "bar", "-a", "b", "input", "output"])
    

    否则你会像这样有效地运行 cmd

    $ cmd --thing\ foo --stuff\ bar -a\ b input output
    

    要将输出放入管道中,您需要稍微不同地调用它

    import subprocess
    output = subprocess.Popen(["cmd", "--thing", "foo", "--stuff", "bar", "-a", "b", "input", "output"],stdout=subprocess.PIPE)
    output.stdout   #  <open file '<fdopen>', mode 'rb'>
    

    【讨论】:

    • subprocess 在返回时似乎没有打印输出。我能做到吗?
    • @Paul Tarjan:这是一个重复的问题。请搜索"[python] subprocess",您将获得该问题的数十个答案。
    【解决方案2】:

    如果您不需要处理代码中的输出,只需在发生时将其显示给用户(从您的 Q 中不清楚,从您自己的答案看来是这样),最简单的是:

    rc = subprocess.call(
        ["cmd", "--thing", "foo", "--stuff", "bar", 
         "-a", "b", "input", "output"])
    print "Return code was", rc
    

    即,避免使用任何管道——让 stdout 和 stderr 只显示在终端上。这应该避免任何缓冲问题。一旦你把管道放在图片中,如果你想在输出发生时显示输出,缓冲通常是一个问题(我很惊讶你的自我回答没有这个问题;-)。 p>

    为了同时显示 捕获,顺便说一句,我总是建议 pexpect(和 Windows 上的 wexpect)完全解决缓冲问题。

    【讨论】:

    • 一如既往,谢谢亚历克斯。 subprocess.call() 似乎缓冲了另一个程序的输出,这不是该程序终端上通常发生的行为。我应该只执行proc = subprocess.Popen 然后在proc.stdout 上执行for 循环打印输出吗?
    • @Paul,不是subprocess 做缓冲——而是另一个程序的 C 运行时库在它注意到它要去管道而不是终端时做它(你观察到的是令人惊讶的,因为 stdout is 将进入终端,因此不应发生缓冲)。 pexpect 使用伪终端来欺骗其他程序的运行时库,从而阻止它们缓冲(Windows 上的wexpect)——我已经多次推荐它们,请搜索我的其他答案以获取它们的 URL。
    【解决方案3】:

    commands.getstatusoutput() 不起作用吗?它会立即返回您的状态。

    【讨论】:

    • 确实如此,但请注意它仅适用于 POSIX(无 Windows)。
    【解决方案4】:

    一位同事刚刚给我看了这个:

    import os
    import sys
    for line in os.popen("cmd --thing foo --stuff bar -a b input output", "r"):
        print line
        sys.stdout.flush()
    

    它正在工作:)

    【讨论】:

    • 您应该使用subprocess 而不是popen。一方面,它让您不必担心转义参数
    • 另一个原因:由于 Python 2.6 os.popen() 被归类为已弃用 subprocess(参见 docs.python.org/library/os.html#os.popen)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-07
    • 2012-12-26
    • 1970-01-01
    相关资源
    最近更新 更多