JOH*_*ÅTT 82 python sigpipe python-3.x
我有一个非常简单的Python 3脚本:
f1 = open('a.txt', 'r')
print(f1.readlines())
f2 = open('b.txt', 'r')
print(f2.readlines())
f3 = open('c.txt', 'r')
print(f3.readlines())
f4 = open('d.txt', 'r')
print(f4.readlines())
f1.close()
f2.close()
f3.close()
f4.close()
Run Code Online (Sandbox Code Playgroud)
但它总是说:
IOError: [Errno 32] Broken pipe
Run Code Online (Sandbox Code Playgroud)
我在互联网上看到了解决这个问题的所有复杂方法,但是我直接复制了这个代码,所以我认为代码有问题而不是Python的SIGPIPE.
我正在重定向输出,所以如果上面的脚本命名为"open.py",那么我的运行命令是:
open.py | othercommand
Run Code Online (Sandbox Code Playgroud)
akh*_*han 111
问题是由于SIGPIPE处理.您可以使用以下代码解决此问题:
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE,SIG_DFL)
Run Code Online (Sandbox Code Playgroud)
mkl*_*nt0 79
带来Alex L.的有用答案, akhan的有用答案,以及Blckknght的有用答案以及一些其他信息:
标准Unix信号SIGPIPE被发送到进程写入到一个管道时,有没有进程读取从管道(了).
head 设计,一旦收到足够的数据,就会从管道中提前停止读取.默认情况下 - 即,如果写入过程没有明确陷阱 SIGPIPE - 写入过程只是终止,并且其退出代码设置为141,计算为128(通常通过信号终止信号)+ 13(SIGPIPE特定信号编号) .
然而,根据设计,Python 本身SIGPIPE会将IOError其陷阱并将其转换为具有errno值的Python实例errno.EPIPE,以便Python脚本可以捕获它,如果它选择的话 - 请参阅Alex L.的答案,了解如何执行此操作.
如果一个Python 脚本并没有抓住它,Python的输出错误信息IOError: [Errno 32] Broken pipe和终止,退出代码脚本1 -这是症状的OP锯.
在许多情况下,这更具破坏性而不是有用,因此需要恢复默认行为:
正如akhan的回答中所述,使用该signal模块就可以实现这一点; 将信号作为第一个参数处理,处理程序作为第二个参数处理; 特殊处理程序值表示系统的默认行为:signal.signal()SIG_DFL
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
Run Code Online (Sandbox Code Playgroud)Ale*_*x L 40
我没有重现这个问题,但也许这个方法可以解决它:(逐行写stdout而不是使用print)
import sys
with open('a.txt', 'r') as f1:
for line in f1:
sys.stdout.write(line)
Run Code Online (Sandbox Code Playgroud)
你能抓到破裂的管子吗?这会将文件stdout逐行写入,直到管道关闭.
import sys, errno
try:
with open('a.txt', 'r') as f1:
for line in f1:
sys.stdout.write(line)
except IOError as e:
if e.errno == errno.EPIPE:
# Handle error
Run Code Online (Sandbox Code Playgroud)
您还需要确保othercommand在管道太大之前从管道读取 - https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer
Blc*_*ght 28
当您尝试写入另一端已关闭的管道时,会出现"Broken Pipe"错误.由于您显示的代码不直接涉及任何管道,我怀疑您正在使用Python之外的东西将Python解释器的标准输出重定向到其他地方.如果你正在运行这样的脚本,可能会发生这种情况:
python foo.py | someothercommand
Run Code Online (Sandbox Code Playgroud)
你遇到的问题someothercommand是没有阅读其标准输入中的所有可用内容而退出.这会导致您的写入(via print)在某些时候失败.
我能够在Linux系统上使用以下命令重现错误:
python -c 'for i in range(1000): print i' | less
Run Code Online (Sandbox Code Playgroud)
如果我在less没有滚动浏览所有输入(1000行)的情况下关闭寻呼机,Python将以IOError您报告的相同方式退出.
tre*_*ehn 19
我觉得有必要指出使用的方法
signal(SIGPIPE, SIG_DFL)
Run Code Online (Sandbox Code Playgroud)
确实是危险的(正如David Bennet在评论中已经提到的那样)并且在我的情况下导致了与平台相关的有趣业务multiprocessing.Manager(因为标准库依赖于在几个地方引发的BrokenPipeError).为了简短而痛苦的故事,这就是我修复它的方法:
首先,您需要捕获IOError(Python 2)或BrokenPipeError(Python 3).根据您的程序,您可以尝试在此时提前退出,或者只是忽略异常:
from errno import EPIPE
try:
broken_pipe_exception = BrokenPipeError
except NameError: # Python 2
broken_pipe_exception = IOError
try:
YOUR CODE GOES HERE
except broken_pipe_exception as exc:
if broken_pipe_exception == IOError:
if exc.errno != EPIPE:
raise
Run Code Online (Sandbox Code Playgroud)
但是,这还不够.Python 3仍然可以打印这样的消息:
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
Run Code Online (Sandbox Code Playgroud)
不幸的是摆脱那条消息并不简单,但我终于找到了http://bugs.python.org/issue11380,其中罗伯特·柯林斯建议这个变通方法,我变成了一个装饰器,你可以用你的主要功能包裹起来(是的,这有些疯狂缩进):
from functools import wraps
from sys import exit, stderr, stdout
from traceback import print_exc
def suppress_broken_pipe_msg(f):
@wraps(f)
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except SystemExit:
raise
except:
print_exc()
exit(1)
finally:
try:
stdout.flush()
finally:
try:
stdout.close()
finally:
try:
stderr.flush()
finally:
stderr.close()
return wrapper
@suppress_broken_pipe_msg
def main():
YOUR CODE GOES HERE
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
164389 次 |
| 最近记录: |