python 子进程: "写入错误:管道中断
我遇到了一个问题,关于如何使用简单的subprocess.Popen来处理数据。
代码如下:
import subprocess
cmd = 'cat file | sort -g -k3 | head -20 | cut -f2,3' % (pattern,file)
p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
for line in p.stdout:
print(line.decode().strip())
对于大约1000行的文件,输出结果是:
...
sort: write failed: standard output: Broken pipe
sort: write error
对于超过241行的文件,输出结果是:
...
sort: fflush failed: standard output: Broken pipe
sort: write error
而对于少于241行的文件,输出结果是正常的。
我一直在阅读文档,也在网上疯狂搜索,但我觉得我对subprocess模块有一些基本的理解没有搞清楚……可能是和缓冲区有关。我试过使用p.stdout.flush(),还调整了缓冲区的大小和p.wait()。我也尝试用像'sleep 20; cat moderatefile'这样的命令来重现这个问题,但似乎没有出现错误。
5 个回答
1
我也遇到了同样的错误。我甚至把管道放进了一个bash脚本里执行,而不是直接在Python中使用管道。在Python中会出现断开的管道错误,但在bash中却没有。
我觉得可能是在head之前的最后一个命令出错了,因为它的输出(STDOUT)被关闭了。Python可能会捕捉到这个错误,而在shell中这个错误是静默的。我把代码改成了处理整个输入,这样错误就消失了。
对于较小的文件来说,这也能解释得通,因为管道可能会在head退出之前先把整个输出缓存起来。这就能解释为什么在处理较大文件时会出现问题。
比如,我原本是想用'head -1'(在我的情况下,我只想要第一行),但我改成了awk 'NR == 1'。
根据'head -X'在管道中的位置,可能还有更好的方法来实现这个功能。
5
这是因为在传给 subprocess.Popen
的命令中不应该使用“shell管道”,你应该使用 subprocess.PIPE
,像这样:
from subprocess import Popen, PIPE
p1 = Popen('cat file', stdout=PIPE)
p2 = Popen('sort -g -k 3', stdin=p1.stdout, stdout=PIPE)
p3 = Popen('head -20', stdin=p2.stdout, stdout=PIPE)
p4 = Popen('cut -f2,3', stdin=p3.stdout)
final_output = p4.stdout.read()
不过我得说,你想做的事情其实可以用纯Python来完成,而不是调用一堆shell命令。
15
来自subprocess文档中的示例:
# To replace shell pipeline like output=`dmesg | grep hda`
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]