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)
在这种微不足道的情况下,至少您不会通过使用 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在每种情况下,第一个示例保留了(本身不可移植,但没关系)的用法,第二个示例产生了效果,尽管我想这不是您具体想要的?