Python 为什么shell=True在将命令管道化时起作用?

Python 为什么shell=True在将命令管道化时起作用?,python,io,subprocess,io-redirection,Python,Io,Subprocess,Io Redirection,我有几个子流程实例,我想串成一个管道,但我被卡住了,想征求建议 例如,要模拟: cat data | foo - | bar - > result 或: 我的第二次尝试使用了一个带有shell=True参数的subprocess实例,该参数可以工作: import subprocess, sys pipedProcess = subprocess.Popen(" ".join(['foo', '-', '|', 'bar', '-']),

我有几个
子流程
实例,我想串成一个管道,但我被卡住了,想征求建议

例如,要模拟:

cat data | foo - | bar - > result
或:

我的第二次尝试使用了一个带有
shell=True
参数的
subprocess
实例,该参数可以工作:

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()
第一个链接的
子流程
方法有什么错?我读到最好不要使用
shell=True
,我很好奇第一种方法哪里做错了。谢谢你的建议

编辑

我修正了问题中的一个输入错误,修正了
secondProcess
stdin
参数。它仍然挂着

我还尝试删除解决挂起问题的
firstProcess.wait()
,但随后我得到一个0字节的文件,名为
result


我将坚持使用
管道流程
,因为它工作正常。但是,如果有人知道第一个安装程序挂起或将0字节文件作为输出的原因,我也很想知道原因。

shell=True
有效,因为您要求shell解释整个命令行并处理管道本身。这就像您直接在shell中键入
foo-| bar-


(这也是为什么使用
shell=True
是不安全的;有很多方法可以欺骗shell做坏事,如果您直接将命令和参数作为一个列表传递进来,而该列表不需要任何中介进行解析,那么就不会发生坏事。)

要修复第一个示例,请将
foo_process.stdout.close()
添加为。以下代码模拟
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  
#!/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()
#!/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()
您不需要在此处明确使用
sys.stdin
sys.stdout
,除非它们与
sys.\uuuuuu stdin\uuuu
sys.\uuuuuu stdout\uuuu
不同

要模拟
foo-result
命令:

#!/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  
#!/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()
#!/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()
如果要将修改后的输入逐行输入到
foo
流程,即模拟
python modify_input.py | 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  
#!/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()
#!/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()

bar
的stdin不应该是
foo
的stdin而不是它的stdin吗?应该是:我输入了一个错误。我已经在我的问题中修复了它。如果你只是将stdin复制到孩子的stdin中,那么
firstProcess=Popen(['foo','-',stdin=sys.stdin,stdout=PIPE)
就行了。我想我添加了一个拼写错误,并打算按照你的方式来做。事实上,我查过了,就是这样。我将相应地编辑我的问题。明白了。我删除了代码,因为它现在是多余的。我应该补充一点,它对我来说非常有效,它为
foo
bar
提供了一些基本的支持,尽管(
sort
uniq
),实际上,它在
stdin
上阅读了一些随机文本。(进一步考虑,这可能是因为
uniq
sort
..之前不会退出)我为什么要使用
bar\u process.communicate()
?我是否会将数据写入
foo\u进程
communicate()
很可能会代替
wait()
,因为
bar\u进程
永远不会向Python提供输出。@AlexReynolds:代码模拟了您的第一个示例(无需先从stdin读取,只需立即将其写入
foo
foo
进程本身即可从stdin读取)。@AlexReynolds:
bar\u进程。stdin没有
所以实际上
bar\u进程。communicate()
只是
bar\u进程。wait()
在本例中。不幸的是,这不起作用。在任何情况下,我都需要一次处理一行数据,并且能够处理除
stdin
之外的文件句柄。它看起来不像sys.stdin中的
行:…bar\u进程。通信(line)
起作用。