IO错误:[错误32]破碎的管:Python之(IOError: [Errno 32] Broken

2019-07-17 23:43发布

我有一个非常简单的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

Answer 1:

我没有复制问题,但也许这种方法可以解决它:(写一行一行到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



Answer 2:

该问题是由于SIGPIPE处理。 您可以使用下面的代码解决这个问题:

from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE,SIG_DFL) 

在这里看到的这个解决方案的背景。 更好的答案在这里 。



Answer 3:

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) 
      


Answer 4:

当您尝试写入已经关闭,另一端的管道时,会发生“断管”的错误。 既然你已经显示的代码并不直接涉及任何管道,我怀疑你正在做的Python之外的东西向Python解释器的标准输出重定向到其他地方。 如果你正在运行一个这样的脚本这种情况可能发生:

python foo.py | someothercommand

你的问题是, someothercommand是不读的标准输入提供一切退出。 这将导致您的写(通过print )在某一时刻失败。

我能够重现错误与Linux系统上运行以下命令:

python -c 'for i in range(1000): print i' | less

如果我收的less寻呼机,而无需通过其所有的输入(1000线)的滚动,Python中退出具有相同IOError您报道。



Answer 5:

我在使用该方法感到有义务指出

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


Answer 6:

如果从脚本输出的读端过早死亡这也可能发生

即open.py | otherCommand

如果otherCommand出口和open.py尝试写入到stdout

我有没有这个可爱的给我一个坏的GAWK脚本。



Answer 7:

我知道这是不是“正确”的方式做到这一点,但如果你是在摆脱错误消息的根本兴趣的话,你可以尝试以下解决方法:

python your_python_code.py 2> /dev/null | other_command


Answer 8:

关闭应在打开了相反的顺序来完成。



文章来源: IOError: [Errno 32] Broken pipe: Python