Python subprocess.Popen块与shell和管道

时间:2014-04-14 15:54:16

标签: python

从shell运行以下命令:yes | head -1,输出y。使用python的子进程模块用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

使用kill外部杀死该过程无济于事,也不会让孩子使用preexec_fn=os.setsid来处理会话负责人。

可能导致这种行为的原因是什么,无论如何我可以阻止它?

我正在运行python 2.7.3而我的/bin/shGNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)

1 个答案:

答案 0 :(得分:0)

事实证明,这是由于python未知在subprocess模块中的exec之前重置信号处理程序的已知问题引起的。

这是导致'yes' reporting error with subprocess communicate()的问题,除了GNU yes之外,写入返回的EPIPE导致程序中止,而使用BSD yes(用于据我所知OS X而言,未检查写入的返回码,因此如果没有SIGPIPEyes将不会终止。

可以通过向后移植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)

然后在preexec_fn=restore_signals来电中设置Popen