将几个子过程连在一起

时间:2011-06-14 09:15:08

标签: python pipe

我有5个进程p1,p2,...,p5我要写一些数据到p1的stdin,管道p1输出到p2 stdin,最后从p5的输出读取最终结果。

到目前为止我尝试过:

p1 = Popen(['p1'], stdin=PIPE, stdout=PIPE)
p2 = Popen(['p2'], stdin=p1.stdout, stdout=PIPE)
...
p5 = Popen(['p5'], stdin=p4.stdout, stdout=PIPE)

# write data to stdin
p1.stdin.write(indata)
p1.stdin.close()

# not sure in what order to close the pipes here, if at all

# read output
out = p5.stdout.read()
print out

最后一段代码被剪掉了,因为我必须不正确地进行读/写操作。

我能够使用communicate()和两个进程来处理单个进程而无需向第一个进程提供任何输入(例如来自Python文档):

output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

但我无法弄清楚,如何在不挂掉解释器的情况下为第一个进程提供输入。

我也可以使用bash脚本(我已经编写并且可以使用),但是我想知道如何用Python实现它。

所以,我想问一下,如何做到这一切,特别是以什么顺序对管道进行读/写/关闭操作?

如果重要的话,我正在使用64位Linux。

编辑:我忘了提到所有进程p1,... p5消耗它们给出的所有输入,处理它,写入stdout然后终止。因此,管道中的下一个流程不应该在前一个流程完成处理之前终止。

EDIT2:我知道我也可以使用

command = 'bash -c "p1 | p2 | p3 | p4 | p5"'
proc = Popen([command], shell=True)
out, err = proc.communicate(input=indata)
print out

但我的主要兴趣是知道如何纯粹用python代码链接管道。

1 个答案:

答案 0 :(得分:8)

也许这会有所帮助:

import sys
import tempfile
from subprocess import Popen, PIPE


cmd = [sys.executable, '-c', 'print raw_input()']

# Using a temp file to give input data to the subprocess instead of stdin.write to avoid deadlocks.
with tempfile.TemporaryFile() as f:
    f.write('foobar')
    f.seek(0)  # Return at the start of the file so that the subprocess p1 can read what we wrote.
    p1 = Popen(cmd, stdin=f, stdout=PIPE)

p2 = Popen(cmd, stdin=p1.stdout, stdout=PIPE)
p3 = Popen(cmd, stdin=p2.stdout, stdout=PIPE)

# No order needed.
p1.stdout.close()
p2.stdout.close()

# Using communicate() instead of stdout.read to avoid deadlocks. 
print p3.communicate()[0]

输出:

$ python test.py
foobar

希望这可以很好。