IOError: Сломанная труба: Python

У меня очень простой скрипт 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 

Я видел в Интернете все сложные способы исправить это, но я скопировал этот код напрямую, поэтому я думаю, что с кодом что-то не так, а не с SIGPIPE Python.

Я перенаправляю вывод, поэтому, если этот выше сценарий был «open.py», тогда моя команда для запуска:

 open.py | othercommand 

    7 Solutions collect form web for “IOError: Сломанная труба: Python”

    Я не воспроизвел эту проблему, но, возможно, этот метод разрешит ее: (запись по stdout в stdout вместо использования print )

     import sys with open('a.txt', 'r') as f1: for line in f1: sys.stdout.write(line) 

    Вы могли поймать сломанную трубу? Это записывает файл в stdout по 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) 

    См. Здесь информацию об этом решении.

    Чтобы привести полезный ответ Алекса Л., полезный ответ ахана и полезный ответ Блеккхтта вместе с дополнительной информацией:

    • Стандартный сигнал Unix SIGPIPE отправляется на процесс записи в трубу, когда нет процесса чтения из трубы (больше).

      • Это не обязательно условие ошибки ; некоторые утилиты Unix, такие как head by design, перестают читать преждевременно из трубы, как только они получают достаточное количество данных.
    • По умолчанию – то есть, если процесс записи явно не SIGPIPE процесс записи просто завершается , а его код выхода устанавливается 141 , который вычисляется как 128 (к завершению сигнала по сигналу в целом) + 13 ( SIGPIPE ' s).

    • По дизайну, однако, сам Python ловушки SIGPIPE и переводит его в экземпляр errno.EPIPE Python с значением errno errno.EPIPE , так что скрипт Python может его поймать, если он так выбирает – см . Ответ Alex L. о том, как это сделать ,

    • Если скрипт Python не поймает его , Python выводит сообщение об ошибке IOError: [Errno 32] Broken pipe и завершает сценарий с кодом выхода 1 – это симптом, который увидел OP.

    • Во многих случаях это более разрушительно, чем полезно , поэтому желательно вернуться к поведению по умолчанию :

      • Использование signal модуля позволяет именно это, как указано в ответе ахана ; signal.signal() принимает сигнал для обработки как 1-й аргумент, а обработчик – второй; значение специального обработчика SIG_DFL представляет собой поведение системы по умолчанию :

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

    Ошибка «Broken Pipe» возникает, когда вы пытаетесь записать в трубу, которая была закрыта на другом конце. Так как код, который вы показали, не содержит прямых труб, я подозреваю, что вы делаете что-то за пределами 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 - лучший язык программирования в мире.