为什么此子流程管道返回不正确的grep结果?

问题描述 投票:0回答:1

我想计算一个大型.fastq文件(5900万行)中大约500个模式的出现。这些模式都正好是20个字符长。

在Unix中,这很简单:

grep -F -o -f patterns.txt big_file.fastq | sort | uniq -c

但是,我希望避免编写临时模式文件,所以我使用python的子进程库创建了一个管道:

from subprocess import Popen, PIPE, STDOUT

p1 = Popen(["grep", "-F", "-o", "-f", "-", "big_file.fastq"], shell = False, stdin = PIPE, stdout = PIPE, stderr= STDOUT)
p2 = Popen(["sort"], shell = False, stdin = p1.stdout, stdout = PIPE, stderr = STDOUT)
p3 = Popen(["uniq", "-c"], shell = False, stdin = p2.stdout, stdout = PIPE, stderr = STDOUT)

然后我在此上调用communication(),提供一个编码的类似于io.StringIO文件的对象作为输入(我使用'-'将其传递给grep命令:]

import io

patterns_file = io.StringIO("\n".join(patterns_list))
p3.communicate(input = patterns_file.read().encode('utf-8'))[0]

当我像这样在uniq上调用communication()时,这可以正常工作。

但是,在测试时,我在管道的第一部分错误地将其称为:

p1.communicate(input = patterns_file.read().encode('utf-8'))[0]

这给了我完全错误的输出,包括比预期的20个字符短或长的匹配。

我不明白为什么会这样。不会在p1上仅调用管道的该部分而忽略其余部分吗?删除p2和p3会使p1正确grep。我觉得我缺少Popen的工作方式。

感谢您的任何帮助。

python grep subprocess pipe popen
1个回答
0
投票

实例化Popen对象时,它们所引用的子过程将立即启动。因此,即使仅在communicate()上调用p1p2p3也正在运行。

为什么这很重要?因为p2仍将其stdin连接到p1正在向其写入输出的FIFO!

如果在您要求Python程序读取相同内容的同时,sort上的p2操作仍在读取内容,则最终将p1的输出分配给它们。可以预计会出现热闹。

© www.soinside.com 2019 - 2024. All rights reserved.