【问题标题】:Why does `subprocess.check_call(..., stderr=sys.stdout)` fail in Python 2.6?为什么 `subprocess.check_call(..., stderr=sys.stdout)` 在 Python 2.6 中失败?
【发布时间】:2016-03-30 14:22:26
【问题描述】:
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 中运行良好。Python 2.6 有何不同之处?

【问题讨论】:

  • 会是路径还是权限? subprocess.check_call(['/bin/echo', 'hi'], stderr=sys.stdout) 有效吗?
  • hm,肯定与 stderr 的重定向有关,虽然我无法快速看到 subprocess.py 中 2.6 和 2.7 之间的变化。
  • @jDo 给出相同的结果。我认为如果这是一个权限问题,在 2.6 和 2.7 中会是一样的吗?
  • 如果你想重定向输出,文档建议直接使用Popen,所以也许这是一种解决方法,尽管找出发生这种情况的原因仍然很有趣。
  • 天哪,即使使用stderr=1 也会发生此错误。 Python 2.7 看到了 很多subprocess 模块工作,很难找出解决此问题的确切更改。

标签: python python-2.6


【解决方案1】:

bug 讨论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
>>> 

发生这种情况是因为我们要求重定向孩子的标准错误,而不是标准输出。所以在 _execute_child 中,errwrite 为 1,而 c2pwrite 为 None。所以 fd 1 (errwrite) 正确地被欺骗为 2。但是,由于 errwrite 不是 None 并且它不在 (p2cread, c2pwrite, 2) 中,孩子关闭 fd 1。

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

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

此补丁针对 2.6.5 版本。

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

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

它已在 2.7 中修复,此 patch 位于相关的 issue 上。

【讨论】:

    猜你喜欢
    • 2017-04-23
    • 2018-02-22
    • 2023-03-16
    • 2018-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多