Python:subprocess.call断管

Dag*_*ang 8 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会显示它?

小智 9

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

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

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

要避免来自cat您的错误消息,可以使用preexec_fnsubprocess.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)
)
Run Code Online (Sandbox Code Playgroud)


Chr*_*gan 2

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

Python 2代码:

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

在 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=='
Run Code Online (Sandbox Code Playgroud)

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