[英]Python subprocess.Popen blocks with shell and pipe
Running the following command: yes | head -1
运行以下命令:
yes | head -1
yes | head -1
, from the shell, outputs y
. 外壳的
yes | head -1
输出y
。 Using python's subprocess module to call it with a shell hangs indefinitely: 使用python的subprocess模块用shell调用它会无限期地挂起:
import subprocess
arg = "yes | head -1"
process = subprocess.Popen(arg,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
print "Command started: %d" % process.pid
r = process.communicate()
print "Command ended: %s %s" % r
Killing the process exogenously using kill
does not help, nor does making the child process it's session leader using preexec_fn=os.setsid
. 使用
kill
外来preexec_fn=os.setsid
进程无济于事,也不能使用preexec_fn=os.setsid
使子进程成为会话的领导者。
What could be causing this behavior, and is there anyway I can prevent it? 是什么导致了此行为,无论如何我可以阻止它吗?
I'm running python 2.7.3 and my /bin/sh
is GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
我正在运行python 2.7.3,而我的
/bin/sh
是GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
So it turns out that this is caused due to a known issue with python not resetting signal handlers before exec in the subprocess
module. 因此,事实证明这是由于python的一个已知问题,即在
subprocess
模块中的exec之前未重置信号处理程序。
This is the same problem that causes 'yes' reporting error with subprocess communicate() , except with GNU yes
, the EPIPE returned by a write causes the program to abort, whereas with BSD yes
(which is used on OS X as far as I can tell), the return code of the write is not checked, so without a SIGPIPE
, yes
will not terminate. 这是导致子进程communication()报告错误的相同问题,但对于GNU
yes
,写入返回的EPIPE导致程序中止,而对于BSD yes
(在OS X上使用可以告诉),写的返回代码不检查,所以没有一个SIGPIPE
, yes
不会终止。
It can be fixed by backporting the reset_signals
code, as in the above linked question: 可以通过向后移植
reset_signals
代码来解决此reset_signals
,如上面的链接问题所示:
def restore_signals():
signals = ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ')
for sig in signals:
if hasattr(signal, sig):
signal.signal(getattr(signal, sig), signal.SIG_DFL)
then setting preexec_fn=restore_signals
in the Popen
call. 然后设置
preexec_fn=restore_signals
在Popen
呼叫。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.