【发布时间】:2011-09-14 13:10:08
【问题描述】:
我有 5 个进程 p1,p2,...,p5 我想将一些数据写入 p1 的标准输入,将 p1 输出通过管道传输到 p2 标准输入,最后从 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 都会消耗它们给出的所有输入,处理它,写入标准输出然后终止。因此,管道中的下一个进程不应在前一个进程完成处理之前终止。
EDIT2:我知道我也可以使用
command = 'bash -c "p1 | p2 | p3 | p4 | p5"'
proc = Popen([command], shell=True)
out, err = proc.communicate(input=indata)
print out
但我的主要兴趣是了解如何纯粹在 python 代码中链接管道。
【问题讨论】:
-
这里有一个相关问题:stackoverflow.com/q/295459/1858225 看来使用显式临时文件(如此处接受的答案)是不需要必要的;但是,似乎没有任何直接且纯粹的 Pythonic 方式来做到这一点,这让我感到惊讶。 Plumbum(在其中一个答案中提到)看起来有点不错,但对我来说太“神奇”了(这是 Python,而不是 Perl!)。完全使用
subprocess(例如sam.nipl.net/code/python/pipeline.py,来自对另一个答案的评论)完成此任务的方法似乎容易出现奇怪的错误。 -
....实际上,我刚刚发现了
pipes模块 (docs.python.org/2/library/pipes.html) 并相应地添加了另一个问题的答案。它看起来比其他解决方案好得多。