Python2.x subprocess.Popen的Broken pipe解决方法

考虑如下代码:

#!/usr/bin/env python
p1 = Popen(["cat", "somebigfile"], stdout = PIPE)
p2 = Popen(["head"], stdin = p1.stdout, stdout = PIPE)
print p2.communicate()[0]

会出现

cat: write error: Broken pipe

原因是在Unix-like系统中,Python启动就会SIG_IGN掉SIG_PIPE,致使cat获取不了SIG_PIPE信号,还向已关闭的管道写入。很久之前就有人提出这个BUG了,这个BUG在Python 3.x已经修复,但是一直没有在Python 2.x实现。

解决方法如下:
1. 下载对应版本的Python源码,找到Lib\subprocess.py(我发现2.6.x的跟2.7.x的就不同)
2. 把该文件放到项目文件夹,改名为sub.py
3. 作如下改动:

--- /usr/lib/python2.6/subprocess.py    2010-04-16 21:58:41.000000000 +0800
+++ sub.py      2011-08-26 17:45:57.576284992 +0800
@@ -429,7 +429,7 @@
     import fcntl
     import pickle
 
-__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError"]
+__all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "CalledProcessError", "_eintr_retry_call"]
 
 try:
     MAXFD = os.sysconf("SC_OPEN_MAX")

4. 新建new_subprocess.py, 建立Popen_new类,继承原来subprocess的Popen,并把sub.py里面Popen类的POSIX版本的_execute_child方法copy过来。

5. 在

if cwd is not None:
	os.chdir(cwd)

后面加上如下代码:

import signal
signals = ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ')
for sig in signals:
	if hasattr(signal, sig):
		signal.signal(getattr(signal, sig), signal.SIG_DFL)

(此处有一个示例,Python 2.6.5版本的)

6. 在项目里

from new_subprocess import Popen_new as Popen

即可


  • Rsj217

    请教 如果是window下出现这样的问题,怎么解决

  • Imgui

    赞一个!另外既然py2系列有这个bug,博主为什么不写patch提交给python官方? hg pull request也可以啊。