我有几个subprocess
个实例,我想把它们串成一个管道,但是我很困难,想请教一下。
例如,模仿:
cat data | foo - | bar - > result
或者:
foo - < data | bar - > result
...我首先尝试了以下内容:
import subprocess, sys
firstProcess = subprocess.Popen(['foo', '-'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
secondProcess = subprocess.Popen(['bar', '-'], stdin=firstProcess.stdout,
stdout=sys.stdout)
for line in sys.stdin:
firstProcess.stdin.write(line)
firstProcess.stdin.flush()
firstProcess.stdin.close()
firstProcess.wait()
我的第二次尝试使用一个带有subprocess
参数的shell=True
实例,该参数有效:
import subprocess, sys
pipedProcess = subprocess.Popen(" ".join(['foo', '-', '|', 'bar', '-']),
stdin=subprocess.PIPE, shell=True)
for line in sys.stdin:
pipedProcess.stdin.write(line)
pipedProcess.stdin.flush()
pipedProcess.stdin.close()
pipedProcess.wait()
第一个链式subprocess
方法我做错了什么?我读到最好不要使用shell=True
,我很好奇第一种方法我做错了什么。谢谢你的建议。
修改
我在问题中修正了拼写错误并修正了stdin
的{{1}}参数。它仍然挂起。
我还尝试删除解析挂起的secondProcess
,但后来我得到一个0字节的文件firstProcess.wait()
。
我会坚持result
,因为它运作正常。但是,如果有人知道为什么第一个设置挂起或将0字节文件作为输出,我也有兴趣知道为什么。
答案 0 :(得分:2)
shell=True
有效,因为您要求shell解释整个命令行并处理管道本身。它实际上就像你直接在shell中输入foo - | bar -
一样。
(这也是使用shell=True
可能不安全的原因;有很多方法可以欺骗shell做坏事,如果你直接将命令和参数作为列表传递给那些不会发生的事情不受任何中介人的解析。)
答案 1 :(得分:1)
要修复第一个示例,请将foo_process.stdout.close()
添加为the docs suggest。以下代码模拟foo - | bar -
命令:
#!/usr/bin/python
from subprocess import Popen, PIPE
foo_process = Popen(['foo', '-'], stdout=PIPE)
bar_process = Popen(['bar', '-'], stdin=foo_process.stdout)
foo_process.stdout.close() # allow foo to know if bar ends
bar_process.communicate() # equivalent to bar_process.wait() in this case
除非与sys.stdin
,sys.stdout
不同,否则您无需在此明确使用sys.__stdin__
,sys.__stdout__
。
模拟foo - < data | bar - > result
命令:
#!/usr/bin/python
from subprocess import Popen, PIPE
with open('data','rb') as input_file, open('result', 'wb') as output_file:
foo = Popen(['foo', '-'], stdin=input_file, stdout=PIPE)
bar = Popen(['bar', '-'], stdin=foo.stdout, stdout=output_file)
foo.stdout.close() # allow foo to know if bar ends
bar.wait()
如果您想逐行向foo
进程提供已修改的输入,即模拟python modify_input.py | foo - | bar -
命令:
#!/usr/bin/python
import sys
from subprocess import Popen, PIPE
foo_process = Popen(['foo', '-'], stdin=PIPE, stdout=PIPE)
bar_process = Popen(['bar', '-'], stdin=foo_process.stdout)
foo_process.stdout.close() # allow foo to know if bar ends
for line in sys.stdin:
print >>foo_process.stdin, "PY", line, # modify input, feed it to `foo`
foo_process.stdin.close() # tell foo there is no more input
bar_process.wait()