Python grep和通过Popen进行管道处理

3
我正在尝试从一个目录中使用grep命令,并将搜索结果限制为前100个。以下代码一直产生以下结果:
[..]
grep: writing output: Broken pipe
grep: writing output: Broken pipe
grep: writing output: Broken pipe
grep: writing output: Broken pipe
[..]

代码如下:
p_grep = Popen(['/bin/bash', '-c', 'grep -F  "asdasdasd" data/*'], stdout = PIPE)
p_head = Popen(['head', '-100'], stdin = p_grep.stdout, stdout = PIPE)
output = p_head.communicate()[0]

如何修复这个问题?

2
尝试这个链接: https://dev59.com/iU3Sa4cB1Zd3GeqPrwou - xkrz
1
@xkrz,那里建议的解决方案难道不就是他正在做的吗? - Rob Wouters
你需要执行grep吗?还是这只是一个例子?否则,grep有一个--max-count选项,你可以使用它来代替整个输出的管道传输。 - GaretJax
max-count 限制了文件中读取的行数,我需要限制所有文件中搜索的数量。 - pistacchio
1
@RobWouters,你是对的,最后给出的例子正是pistcchio正在做的。我很抱歉没有完整地阅读其他帖子。 - xkrz
2个回答

1

实际上在这种情况下,你可以这样做:

output = check_output(['/bin/bash', '-c', 'grep -F  "asdasdasd" data/* | head -100'])

问题在于,我不知道为什么它会执行所有的 grepping 然后再通过 head 进行管道处理,因此,虽然在 shell 中只需要几秒钟,但在 Python 中需要更长的时间。 - pistacchio
@pistacchio,你可以尝试在grep命令中加入--line-buffered参数,看看是否有所改变? - Rob Wouters
我想不出为什么会有差异的原因。你确定你在比较完全相同的命令吗?唯一可能的是尝试传递 bufsize=1check_output - Rob Wouters

0
根据Popen文档中有关编写管道的说明,您应该确保关闭管道进程(在本例中为p_grep)上的stdout,以便它们能够从被管道连接的进程(在本例中为p_head)接收SIGPIPE
此外,根据这篇文章,重要的是为每个子进程提供设置函数,以便将Python对SIGPIPE的处理恢复到其默认行为。
因此,代码变为:
def preexec_fn():
    import signal
    signal.signal(signal.SIGPIPE, signal.SIG_DFL)

p_grep = Popen(['/bin/bash', '-c', 'grep -F  "asdasdasd" data/*'], stdout=PIPE, preexec_fn=preexec_fn)
p_head = Popen(['head', '-100'], stdin=p_grep.stdout, stdout=PIPE, preexec_fn=preexec_fn)
p_grep.stdout.close()
output = p_head.communicate()[0]

这应该会导致 grep 进程在 head 完成后终止。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接