【问题标题】:Python: subprocess.call broken pipePython:subprocess.call 损坏的管道
【发布时间】:2012-05-15 19:51:55
【问题描述】:

我试图在 python 中调用一个 shell 脚本,但它一直报告损坏的管道错误(结果是好的,但我不想在 STDERR 中看到错误消息)。已经查明原因,可以复现为如下sn-p:

subprocess.call('cat /dev/zero | head -c 10 | base64', shell=True)

AAAAAAAAAAAAAAA==

cat:写入错误:管道损坏

/dev/zero 是一个无限流,但head -c 10 只从中读取 10 个字节并退出,然后 cat 将获得 SIGPIPE,因为对等方已关闭管道。我在shell中运行命令时没有损坏管道错误消息,但是为什么python会显示它?

【问题讨论】:

  • 跳过uuoc:subprocess.call('head -c 10 < /dev/zero | base64', shell=True)时错误消失
  • @larsmans:你可以把它作为答案
  • @ChrisMorgan:实际上,我非常喜欢你的回答。
  • @larsmans:这取决于他在做什么。如果不是像headbase64 这样简单的东西,在纯Python 中管理起来可能太难了。你的问题解决了as ask,这是有价值的。
  • @ChrisMorgan:是的。不过,如果我了解发生了什么,我只会发布答案,而我没有。我以前从未见过cat 抱怨管道破裂,并且一直依靠管道关闭时它默默退出。

标签: python bash subprocess


【解决方案1】:

SIGPIPE 信号的默认操作是终止程序。 Python 解释器将其更改为 SIG_IGN,以便能够以异常的形式向程序报告损坏的管道错误。

当您在 shell 中执行 cat ... |head ... 时,cat 具有默认的 SIGPIPE 处理程序,操作系统内核只是在 SIGPIPE 上终止它。

当您使用subprocess 执行cat 时,它会从其父级(python 解释器)派生 SIGPIPE 处理程序,SIGPIPE 将被忽略,cat 通过检查errno 变量并打印错误消息来处理错误本身。

为避免来自cat 的错误消息,您可以在 subprocess.call 中使用preexec_fn 参数:

from signal import signal, SIGPIPE, SIG_DFL
subprocess.call(
    'cat /dev/zero | head -c 10 | base64',
    shell = True,
    preexec_fn = lambda: signal(SIGPIPE, SIG_DFL)
)

【讨论】:

  • 太好了,非常感谢,刚刚使用 cat 解决了我的 shell 脚本问题(我很确定它不是 uuoc,也许这是另一个问题!)。
  • 太棒了!修复了一个 tr:broken pipe 错误,由使用 subprocess.call() 调用 bash 脚本引起的
【解决方案2】:

在这种微不足道的情况下,至少您没有通过使用 shell 命令获得任何好处——而且您正在失去可移植性和速度。

Python 2 代码:

>>> import base64
>>> base64.b64encode(open('/dev/zero', 'rb').read(10))
'AAAAAAAAAAAAAA=='
>>> base64.b64encode('\0' * 10)
'AAAAAAAAAAAAAA=='

在 Python 3 中(代码也将在 2.6+ 中运行,尽管它会返回 str 而不是 bytes 实例):

>>> import base64
>>> base64.b64encode(open('/dev/zero', 'rb').read(10))
b'AAAAAAAAAAAAAA=='
>>> base64.b64encode(b'\0' * 10)
b'AAAAAAAAAAAAAA=='

在每种情况下,第一个示例都保留了/dev/zero 的用法(本身不可移植,但没关系),第二个产生了效果,尽管我想这不是你想要的?

【讨论】:

  • +1。 '\x00' 也可以写成 '\0'(或 Python 3.x 中的 b'\0')。
  • 我想我更喜欢 subdir 的答案,它直接解决了问题,并解释了问题。
猜你喜欢
  • 2010-10-28
  • 2011-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-21
  • 1970-01-01
相关资源
最近更新 更多