在python子进程模块中,如果我们想运行shell命令
foo | grep bar
从python中,我们可能会使用
p1 = Popen(["foo"], stdout = PIPE)
p2 = Popen(["grep", "bar"], stdin = p1.stdout, stdout = PIPE)
p1.stdout.close()
output = p2.communicate()[0]
我对行p1.stdout.close()
感到困惑。如果你原谅我,我将追溯我认为该程序是如何运作的,并且错误将有希望揭示出来。
在我看来,当行output = p2.communicate()[0]
由python制定时,python会尝试调用p2
,它会识别它需要p1
的输出。因此它调用p1
,执行foo
并将输出抛出到堆栈上,以便p2
可以完成执行。然后p2
结束。
但在这个追踪中没有任何地方p1.stdout.close()
实际发生。那么实际发生了什么?在我看来,这种行的排序也可能很重要,因此以下方法不起作用:
p1 = Popen(["foo"], stdout = PIPE)
p1.stdout.close()
p2 = Popen(["grep", "bar"], stdin = p1.stdout, stdout = PIPE)
output = p2.communicate()[0]
这就是我的理解状态。
答案 0 :(得分:4)
p1.stdout.close()
是foo
检测管道何时损坏所必需的,例如p2
过早退出。
如果没有p1.stdout.close()
,那么p1.stdout
在父进程中保持打开状态,即使p2
退出也是如此; p1
将不会知道没有人读取p1.stdout
,即p1
将继续写入p1.stdout
,直到相应的OS管道缓冲区已满,然后它才会永久阻塞。 / p>
在没有shell的情况下模拟foo | grep bar
shell命令:
#!/usr/bin/env python3
from subprocess import Popen, PIPE
with Popen(['grep', 'bar'], stdin=PIPE) as grep, \
Popen(['foo'], stdout=grep.stdin):
grep.communicate()
请参阅How do I use subprocess.Popen to connect multiple processes by pipes?