我有一个非常简单的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()
但是,它总是说:
IOError: [Errno 32] Broken pipe
我看到在互联网上的所有复杂的方式来解决这个问题,但我直接复制此代码,所以我觉得有什么不对的代码,而不是Python的SIGPIPE。
我重定向输出,因此,如果上面的脚本被命名为“open.py”,那么我的命令来运行将是:
open.py | othercommand
我没有复制问题,但也许这种方法可以解决它:(写一行一行到stdout
,而不是使用print
)
import sys
with open('a.txt', 'r') as f1:
for line in f1:
sys.stdout.write(line)
你可以赶上破裂的管道? 这将文件写入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
您还需要确保othercommand
从管道读取它变得太大之前- https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer
该问题是由于SIGPIPE处理。 您可以使用下面的代码解决这个问题:
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE,SIG_DFL)
在这里看到的这个解决方案的背景。 更好的答案在这里 。
To bring Alex L.'s helpful answer, akhan's helpful answer, and Blckknght's helpful answer together with some additional information:
Standard Unix signal SIGPIPE
is sent to a process writing to a pipe when there's no process reading from the pipe (anymore).
- This is not necessarily an error condition; some Unix utilities such as
head
by design stop reading prematurely from a pipe, once they've received enough data.
By default - i.e., if the writing process does not explicitly trap SIGPIPE
- the writing process is simply terminated, and its exit code is set to 141
, which is calculated as 128
(to signal termination by signal in general) + 13
(SIGPIPE
's specific signal number).
By design, however, Python itself traps SIGPIPE
and translates it into a Python IOError
instance with errno
value errno.EPIPE
, so that a Python script can catch it, if it so chooses - see Alex L.'s answer for how to do that.
If a Python script does not catch it, Python outputs error message IOError: [Errno 32] Broken pipe
and terminates the script with exit code 1
- this is the symptom the OP saw.
In many cases this is more disruptive than helpful, so reverting to the default behavior is desirable:
Using the signal
module allows just that, as stated in akhan's answer; signal.signal()
takes a signal to handle as the 1st argument and a handler as the 2nd; special handler value SIG_DFL
represents the system's default behavior:
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
当您尝试写入已经关闭,另一端的管道时,会发生“断管”的错误。 既然你已经显示的代码并不直接涉及任何管道,我怀疑你正在做的Python之外的东西向Python解释器的标准输出重定向到其他地方。 如果你正在运行一个这样的脚本这种情况可能发生:
python foo.py | someothercommand
你的问题是, someothercommand
是不读的标准输入提供一切退出。 这将导致您的写(通过print
)在某一时刻失败。
我能够重现错误与Linux系统上运行以下命令:
python -c 'for i in range(1000): print i' | less
如果我收的less
寻呼机,而无需通过其所有的输入(1000线)的滚动,Python中退出具有相同IOError
您报道。
我在使用该方法感到有义务指出
signal(SIGPIPE, SIG_DFL)
确实是危险的 (如已经由大卫贝内特的意见建议),并在我的情况,即随着结合导致依赖于平台的滑稽的生意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
然而,这还远远不够。 Python 3里仍然可以打印这样的消息:
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
不幸的是摆脱该消息并不简单,但我终于找到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
如果从脚本输出的读端过早死亡这也可能发生
即open.py | otherCommand
如果otherCommand出口和open.py尝试写入到stdout
我有没有这个可爱的给我一个坏的GAWK脚本。
我知道这是不是“正确”的方式做到这一点,但如果你是在摆脱错误消息的根本兴趣的话,你可以尝试以下解决方法:
python your_python_code.py 2> /dev/null | other_command