我试图在 python 中调用一个 shell 脚本,但它一直报告 broken pipe 错误(结果没问题,但我不想在 STDERR 中看到错误消息)。我已经查明了原因,它可以重现为以下片段:
subprocess.call('cat/dev/zero | head -c 10 | base64', shell=True)
AAAAAAAAAAAAAAAA==
猫:写入错误:管道损坏
/dev/zero
是一个无限流,但是 head -c 10
只从中读取 10 个字节就退出了,然后 cat 会因为 peer 而得到 SIGPIPE已关闭管道。在 shell 中运行命令时没有 broken pipe 错误消息,但为什么 python 显示它?
最佳答案
SIGPIPE 信号的默认操作是终止程序。 Python 解释器将其更改为 SIG_IGN,以便能够以异常的形式向程序报告损坏的管道错误。
当你在 shell 中执行 cat ... |head ...
时,cat
有默认的 SIGPIPE 处理程序,操作系统内核只是在 SIGPIPE 上终止它。
当您使用 subprocess
执行 cat
时,它会从其父进程(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)
)
关于Python:subprocess.call 破管,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10479825/