将来自许多有用答案的信息与一些附加信息结合在一起:
SIGPIPE
当没有进程从管道读取时(不再),标准 Unix 信号被发送到写入管道的进程。
- 这不一定是错误情况;某些 Unix 实用程序(例如
head
设计使然)一旦接收到足够的数据,就会过早地停止从管道中读取。
- 因此,引发此错误的一种简单方法是通过管道传输到
head
[1];例如:
python -c 'for x in range(10000): print(x)' | head -n 1
默认情况下- 即如果写入过程没有显式陷阱 SIGPIPE
141
-128
写入过程简单终止,其退出代码设置为.13
SIGPIPE
但是,根据设计,Python本身会捕获SIGPIPE
并将其转换为BrokenPipeError
IOError
errno
具有value的 Python (Python 3) / (Python 2)实例errno.EPIPE
。
- 注意:如果您在 Windows 上使用 Unix 仿真环境,错误可能会有所不同 - 请参阅此答案。
如果 Python脚本没有捕获异常,Python会输出错误消息BrokenPipeError: [Errno 32] Broken pipe
(Python 3,可能两次,Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
夹在中间)/ IOError: [Errno 32] Broken pipe
(Python 2)并使用退出代码[2]终止脚本1
- 这是 Johannes 的症状(OP ) 锯。
Windows注意事项(SIGPIPE
仅 Unix 信号)
有两种方法可以解决这个问题:
通常,不建议将此异常静音,因为它可能表示严重的错误情况,具体取决于脚本的用途,例如网络套接字的接收端意外关闭。
- 但是,如果您的脚本是一个命令行实用程序,那么安静终止可能不仅可以接受而且是首选,以便与标准
head
实用程序很好地配合,例如,您可以按照以下方式安静地中止signal.signal()
,用于安装平台的默认信号处理程序(其行为如上所述),也如akhan 的回答所示(适用于 Python 3 和 2):
# ONLY SUITABLE FOR COMMAND-LINE UTILITIES
# Install the default signal handler.
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
# Start printing many lines.
# If this gets interrupted with SIGPIPE,
# the script aborts quietly, and the process exit code is set to
# 141 (128 + SIGPIPE)
for x in range(10000): print(x)
- 否则,如果您想自己处理 SIGPIPE 触发的异常(适用于 Python 3 和 2,改编自docs):
import sys, os, errno
try:
# Start printing many lines.
for x in range(10000): print(x)
# IMPORTANT: Flush stdout here, to ensure that the
# SIGPIPE-triggered exception can be caught.
sys.stdout.flush()
except IOError as e:
# Note: Python 3 has the more specific BrokenPipeError,
# but this way the code works in Python 2 too.
if e.errno != errno.EPIPE: raise e # Unrelated error, re-throw.
# Python flushes standard streams on exit; redirect remaining output
# to devnull to avoid another BrokenPipeError at shutdown
devnull = os.open(os.devnull, os.O_WRONLY)
os.dup2(devnull, sys.stdout.fileno())
# ... perform other handling.
# Note: You can't write to stdout here.
# (print() and sys.stdout.write won't work)
# However, sys.stderr.write() can be used.
sys.stderr.write("SIGPIPE received, terminating.\n")
# Finally, exit with an exit code of choice.
sys.exit(141)
[1] 请注意,bash
默认情况下,您只会看到head
' 退出代码 - 这是0
- 反映在$?
之后。用于echo ${PIPESTATUS[0]}
查看 Python 的退出代码。
[2] 奇怪的是,在 macOS 10.15.7 (Catalina) 和 Python 3.9.2(但不是 2.x)上,我看到了 exit code 120
,但文档说1
,这也是我在 Linux 上看到的。