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)
起作用。