Python:subprocess.call断管

时间:2012-05-07 09:40:02

标签: python bash subprocess

我正在尝试在python中调用shell脚本,但它一直报告管道错误(结果没问题,但我不想在STDERR中看到错误消息)。我已经确定了原因,可以将其复制为以下片段:

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

AAAAAAAAAAAAAA ==

cat:写入错误:管道损坏

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

2 个答案:

答案 0 :(得分:8)

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

在shell中执行cat ... |head ...时,cat具有默认的SIGPIPE处理程序,而OS内核只是在SIGPIPE上终止它。

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

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

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)
)

答案 1 :(得分: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的使用(本身是非便携式,但没关系),第二个例子产生效果,虽然我想它不是你想要的具体?