为什么`subprocess.check_call(...,stderr = sys.stdout)`在Python 2.6中失败?

时间:2016-03-30 14:22:27

标签: python python-2.6

Python 2.6.9 (unknown, Mar  7 2016, 11:15:18) 
[GCC 5.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> import subprocess
>>> subprocess.check_call(['echo', 'hi'], stderr=sys.stdout)
echo: write error: Bad file descriptor
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.6/subprocess.py", line 488, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['echo', 'hi']' returned non-zero exit status 1

这个命令subprocess.check_call(['echo', 'hi'], stderr=sys.stdout)在Python 2.7和Python 3中运行得很好.PySQL 2.6的做法有何不同?

1 个答案:

答案 0 :(得分:6)

讨论了这个错误here

Transcript to reproduce in Python 2.6.5:

>>> import subprocess, sys
>>> subprocess.call(('echo', 'foo'), stderr=sys.stdout)
echo: write: Bad file descriptor
1
>>> 

Expected behavior:

>>> import subprocess, sys
>>> subprocess.call(('echo', 'foo'), stderr=sys.stdout)
foo
0
>>> 
  

这是因为我们已经要求孩子的stderr被重定向,而不是它的stdout。所以在_execute_child中,errwrite为1而c2pwrite为None。所以fd 1(errwrite)正确地被骗到2.但是,因为errwrite不是None而且它不在(p2cread,c2pwrite,2)中,所以孩子关闭了fd 1.

     

如果您提供stdout = sys.stderr并且子项尝试写入其stderr,则会发生同等的事情。

     

我附上了一个补丁来解决这个问题。它只是将fds列表中的2和2分别添加为不关闭c2pwrite和errwrite。

     

此补丁违反2.6.5版本。

     

还有一种解决方法,以防其他人在修复发布之前受到此错误的影响:

>>> import os, subprocess, sys
>>> subprocess.call(('echo', 'foo'), stderr=os.dup(sys.stdout.fileno()))
foo
0
>>> 

在相关的patch上使用此issue修复了2.7。