8

我想使用一个相当于在 perl 中管道一些 shell 命令的 python。类似于 python 版本的 open(PIPE, "command |")。

我转到子流程模块并尝试以下操作:

p = subprocess.Popen("zgrep thingiwant largefile", shell=True, stdout=subprocess.PIPE)

这适用于读取输出的方式与我在 perl 中的方式相同,但它不会自行清理。当我退出解释器时,我得到

grep: writing output: Broken pipe

在 stderr 上喷了几百万次。我想我曾天真地希望这一切都会为我处理好,但事实并非如此。在 p 上调用 terminate 或 kill 似乎没有帮助。查看进程表,我看到这会杀死 /bin/sh 进程,但将子 gzip 留在原地抱怨管道损坏。

这样做的正确方法是什么?

4

4 回答 4

11

问题是pipe已经满了。子进程停止,等待管道清空,但随后您的进程(Python 解释器)退出,破坏了管道的末端(因此出现错误消息)。

p.wait()不会帮助你:

警告如果子进程生成足够的输出到 stdout 或 stderr 管道,从而阻塞等待 OS 管道缓冲区接受更多数据,这将死锁。用来communicate()避免这种情况。

http://docs.python.org/library/subprocess.html#subprocess.Popen.wait

p.communicate()不会帮助你:

注意读取的数据是缓存在内存中的,所以如果数据量很大或没有限制,请不要使用此方法。

http://docs.python.org/library/subprocess.html#subprocess.Popen.communicate

p.stdout.read(num_bytes)不会帮助你:

警告使用communicate()而不是.stdin.write.stdout.read.stderr.read避免由于任何其他操作系统管道缓冲区填满并阻塞子进程而导致的死锁。

http://docs.python.org/library/subprocess.html#subprocess.Popen.stdout

这个故事的寓意是,对于大输出,subprocess.PIPE如果你的程序试图读取数据,你注定会失败(在我看来,你应该能够p.stdout.read(bytes)进入一个while p.returncode is None:循环,但上面的警告表明这可能僵局)。

文档建议用这个替换一个shell pipe:

p1 = Popen(["zgrep", "thingiwant", "largefile"], stdout=PIPE)
p2 = Popen(["processreceivingdata"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

请注意,p2它直接从p1. 这应该可以避免死锁,但鉴于上面的矛盾警告,谁知道呢

无论如何,如果最后一部分对您不起作用(但它应该),您可以尝试创建一个临时文件,将第一次调用中的所有数据写入该文件,然后将临时文件用作下一个进程的输入。

于 2010-04-08T20:41:33.653 回答
3

打开管道后,您可以使用命令输出p.stdout

for line in p.stdout:
    # do stuff
p.stdout.close()
于 2010-04-08T00:05:41.333 回答
0

你是如何执行这个过程的?

正确的方法是使用

p.communicate()

有关更多详细信息,请参阅文档。

于 2010-04-07T20:25:02.597 回答
0

您需要wait完成该过程:

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True)
p.wait()

或者,您可以捕获程序的标准输出(正如您所拥有的),也许还有它的标准错误,然后调用communicate

import subprocess
p = subprocess.Popen("cat /mach_kernel", shell=True,
                     stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
于 2010-04-08T20:21:31.580 回答