简体   繁体   English

Python subprocess.Popen带有外壳和管道的块

[英]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/shGNU 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上使用可以告诉),写的返回代码不检查,所以没有一个SIGPIPEyes不会终止。

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_signalsPopen呼叫。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM