【问题标题】:Running an external program from python: piping without waiting for all output从 python 运行外部程序:管道而不等待所有输出
【发布时间】:2014-02-25 21:11:19
【问题描述】:

我查看了Calling an external command in Python 并尝试了所有可能的方法来使用 subprocess 和 os.popen 但似乎没有任何效果。

如果我尝试

import os
stream = os.popen("program.ex -f file.dat | grep fish | head -4")

我得到了一行一行

grep: broken pipe

如果我切换 grephead 命令,它永远不会到达 grep 命令,因为 program.ex 的输出非常长(这就是我使用 head -4 运行的原因)。

当然,由于管道,以下失败:

import subprocess as sp
cmd = "program.ex -f file.dat | grep fish | head -4"
proc = sp.Popen(cmd.split(),stdout=sp.PIPE,stderr=sp.PIPE)
stdout, stderr = proc.communicate()

所以我试着把它分解

cmd1 = "program.ex -f file.ex"
cmd2 = "head -4"
cmd3 = "grep fish"
proc1 = sp.Popen(cmd1.split(),stdout=sp.PIPE,stderr=sp.PIPE)
proc2 = sp.Popen(cmd2.split(),stdout=sp.PIPE,stdin=proc1.stdout)
proc3 = sp.Popen(cmd3.split(),stdout=sp.PIPE,stdin=proc2.stdout)
stdout, stderr = proc1.communicate()

它确实可以运行,除了它卡在 cmd1 上,因为 program.ex 的输出太长了。

最后我尝试将其隐藏在外部 shell 脚本和 fortran 程序中,但 fortran 程序做了一个

call system("program.ex -f file.dat | grep fish | head -4")

我猜这又把 python 搞砸了。

注意:如果我直接在终端中执行此操作,则不需要从 program.ex 获取整个输出,并且命令会立即完成。

所以,我的问题是:

我怎样才能让上述命令像在终端中一样在 python 中运行(即,head 并 grep program.ex 的输出,而无需等待 program.ex 的所有输出)?

非常感谢您的帮助!

编辑:

我也试过shell=True

import subprocess as sp
cmd = "program.ex -f file.dat | head -4 | grep fish"
proc = sp.Popen(cmd.split(),stdout=sp.PIPE,stderr=sp.PIPE,shell=True)
stdout, stderr = proc.communicate()

确实运行了,虽然 stderr 有预期的(不需要的)内容,但 stdout 是空的。如果我将上面的 cmd 变量替换为调用系统命令的 fortran 程序的名称,那么它会再次挂在 program.ex 上,可能正在等待所有输出完成。

【问题讨论】:

  • 对于shell=True,对Popen() 的命令应该是一个字符串。 (不幸的是,我也无法使用 shell=True。)

标签: python bash shell python-2.7 subprocess


【解决方案1】:

您可以使用 bash 来处理管道。

只能运行脚本文件,不能运行命令(bash -e echogiving/bin/echo: /bin/echo: cannot execute binary file)

bash -e <script to run>

如果您将命令放在脚本文件中,它将运行它们

【讨论】:

    【解决方案2】:

    这仍然给我在第一个过程中的 stderr 中的各种错误,但也许它仍然足以满足您的目的?使用您的多管道示例,但在 output 进程上调用 .communicate()

    import subprocess
    cmd1 = ['yes', 'fishy'] # is this similar enough to your example program?
    cmd2 = ['head', '-4']
    cmd3 = ['grep', 'fish']
    proc1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    proc2 = subprocess.Popen(cmd2, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                             stdin=proc1.stdout)
    proc3 = subprocess.Popen(cmd3, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                             stdin=proc2.stdout)
    result, err3 = proc3.communicate()
    proc2.wait()
    err2 = proc2.stderr.read()
    proc1.stdout.close()
    proc1.wait()
    err1 = proc1.stderr.read() # 'yes: standard output: Broken pipe\nyes: write error\n'
    

    【讨论】:

      【解决方案3】:

      这个令人惊叹但鲜为人知的库可能正是您想要的:

      https://github.com/kennethreitz/envoy

      请务必使用 Github 版本,而不是使用 pip 安装的版本。顺便说一句,这只是一个文件。

      【讨论】:

        猜你喜欢
        • 2018-11-19
        • 1970-01-01
        • 1970-01-01
        • 2019-10-27
        • 2017-08-08
        • 1970-01-01
        • 2019-01-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多