从python运行外部程序:管道而不等待所有输出

时间:2014-02-02 10:26:43

标签: python bash shell python-2.7 subprocess

我查看过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中运行(即,从program.ex输出并grep输出而无需等待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上,可能等待所有输出完成。

3 个答案:

答案 0 :(得分:0)

这个令人惊叹但却不为人知的图书馆可能正是您所寻找的:

https://github.com/kennethreitz/envoy

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

答案 1 :(得分:0)

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

它只能运行脚本文件而且不会运行命令(bash -e echo给出/bin/echo: /bin/echo: cannot execute binary file

bash -e <script to run>

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

答案 2 :(得分:0)

这仍然让我在第一个进程中出现了stderr中的错误,但是它仍然可以用于你的目的吗?使用多个管道示例,但在输出进程上调用.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'