У меня очень простой скрипт 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
python
python-3.x
sigpipe
JOHANNES_NYÅTT
источник
источник
print(f1.readlines())
a.txt
и запись вstdout
. Возможно, попробуйте разделить их на отдельные строки, чтобы увидеть, какая операция вызывает исключение. Еслиstdout
это канал и конец чтения был закрыт, это может объяснитьEPIPE
ошибку.print
вызов. @ JOHANNES_NYÅTT, не могли бы вы пояснить, как вы запускаете свой скрипт Python? Вы куда-то перенаправляете стандартный вывод?Ответы:
Я не воспроизводил проблему, но, возможно, этот метод решит ее: (запись строка за строкой
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
он читает из канала, прежде чем он станет слишком большим - /unix/11946/how-big-is-the-pipe-bufferисточник
print
вызовом, а не с чтением файлов).Проблема связана с обработкой SIGPIPE. Вы можете решить эту проблему, используя следующий код:
from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE,SIG_DFL)
См. Здесь информацию об этом решении. Лучше ответь здесь .
источник
Для того, чтобы принести полезный ответ Алекс Лоэнгрина , полезный ответ Ахан игровая и полезный ответ Blckknght в вместе с некоторой дополнительной информацией:
Стандартный сигнал Unix
SIGPIPE
отправляется процессу, записывающему в канал, когда процесс не читает из канала (больше).head
, изначально прекращают считывание данных из конвейера преждевременно, как только они получили достаточно данных.По умолчанию - то есть, если процесс записи явно не перехватывает
SIGPIPE
- процесс записи просто завершается , и для него устанавливается код выхода141
, который рассчитывается как128
(для сигнала завершения сигналом в целом) +13
(SIGPIPE
конкретный номер сигнала ) .Однако по своей задумке Python сам улавливает
SIGPIPE
и преобразует его вIOError
экземпляр Python соerrno
значениемerrno.EPIPE
, так что скрипт Python может поймать его, если он того пожелает - см . Ответ Alex L. о том, как это сделать.Если Python скрипт никак не поймать его , Python выводит сообщение об ошибке
IOError: [Errno 32] Broken pipe
и завершает сценарий с кодом выхода1
- это симптом ОП видел.Во многих случаях это скорее разрушительно, чем полезно , поэтому желательно вернуться к поведению по умолчанию :
Использование
signal
модуля позволяет именно это, как указано в ответе Ахана ;signal.signal()
принимает сигнал для обработки как 1-й аргумент и обработчик как 2-й; специальное значение обработчикаSIG_DFL
представляет поведение системы по умолчанию :from signal import signal, SIGPIPE, SIG_DFL signal(SIGPIPE, SIG_DFL)
источник
Ошибка «Сломанный канал» возникает при попытке записи в канал, который был закрыт на другом конце. Поскольку показанный вами код не включает напрямую какие-либо каналы, я подозреваю, что вы делаете что-то вне Python, чтобы перенаправить стандартный вывод интерпретатора Python в другое место. Это может произойти, если вы запустите такой сценарий:
Проблема заключается в том, что
someothercommand
вы закрываетесь, не читая все, что доступно на стандартном вводе. Это приводитprint
к сбою вашей записи (через ) в какой-то момент.Мне удалось воспроизвести ошибку с помощью следующей команды в системе Linux:
python -c 'for i in range(1000): print i' | less
Если я
less
закрою пейджер без прокрутки всего ввода (1000 строк), Python завершит работу с тем же значением, о которомIOError
вы сообщили.источник
SIGPIPE
сигнал не обязательно указывает на ошибки условие, некоторые Unix утилиты, в частностиhead
, в соответствии с проектом, во время нормальной работы вблизи трубы рано, как только они прочитают столько данных, сколько им нужно.Я считаю своим долгом отметить, что метод, использующий
действительно опасно (как уже было предложено Дэвидом Беннетом в комментариях) и в моем случае привело к зависящему от платформы забавному бизнесу в сочетании с
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
источник
Я знаю, что это не «правильный» способ сделать это, но если вы просто хотите избавиться от сообщения об ошибке, вы можете попробовать следующее обходное решение:
python your_python_code.py 2> /dev/null | other_command
источник
Главный ответ (
if e.errno == errno.EPIPE:
) здесь не сработал для меня. Я получил:AttributeError: 'BrokenPipeError' object has no attribute 'EPIPE'
Однако это должно работать, если все, что вас волнует, - это игнорирование сломанных каналов при определенных операциях записи. Думаю, это безопаснее, чем перехватить SIGPIPE:
try: # writing, flushing, whatever goes here except BrokenPipeError: exit( 0 )
Вы, очевидно, должны принять решение относительно того, действительно ли ваш код выполнен, если вы столкнетесь с поломкой трубы, но для большинства целей я думаю, что обычно это правда. (Не забудьте закрыть дескрипторы файлов и т. Д.)
источник
Это также может произойти, если конец чтения вывода из вашего скрипта преждевременно умирает
т.е. open.py | otherCommand
если otherCommand завершается и open.py пытается записать в stdout
У меня был плохой сценарий gawk, который мне так понравился.
источник
head
, по дизайну, во время нормальной работы закрывают конвейер раньше, как только они прочитали столько данных, сколько им нужно. Большинство интерфейсов командной строки просто подчиняются системе за ее поведение по умолчанию: незаметное завершение процесса чтения и сообщение кода выхода141
(который в оболочке не всегда очевиден, потому что последняя команда конвейера определяет общий код выхода). К сожалению, поведение Python по умолчанию - шумно умирать .Закрытие должно производиться в порядке, обратном открытию.
источник