Programing

IOError : [Errno 32] 깨진 파이프 : Python

crosscheck 2020. 10. 11. 09:07
반응형

IOError : [Errno 32] 깨진 파이프 : 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

인터넷에서이 문제를 해결하는 모든 복잡한 방법을 보았지만이 코드를 직접 복사했기 때문에 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) 

이 솔루션에 대한 배경 정보는 여기참조하십시오 . 여기에 더 나은 대답 .


가져 알렉스 L.의 도움이 대답 , akhan의 도움이 대답 하고, Blckknght의 도움이 대답을 몇 가지 추가 정보와 함께 :

  • 표준 유닉스 신호가SIGPIPE 프로세스로 전송 쓰기 A를 파이프 어떤 프로세스가 없을 때 읽기 파이프 (더 이상)에서이.

    • 이것은 반드시 오류 조건 은 아닙니다 . head 설계 상 일부 유닉스 유틸리티 는 충분한 데이터를 수신하면 파이프에서 읽기를 일찍 중지합니다.
  • 기본적으로 -즉, 쓰기 프로세스가 명시 적으로 트랩 하지 않는 경우 SIGPIPE-쓰기 프로세스가 단순히 종료 되고 종료 코드가로 설정됩니다141 . 이는 128(일반적으로 신호에 의한 신호 종료) + 13( SIGPIPE의 특정 신호 번호 )로 계산됩니다. .

  • 그러나 설계 상 Python 자체SIGPIPE값이 있는 PythonIOError 인스턴스 트랩 하고 변환 하므로 Python 스크립트가 원하는 경우이를 포착 할 수 있습니다 . 수행 방법 Alex L.의 답변참조하십시오 .errnoerrno.EPIPE

  • 파이썬 경우 스크립트가 않습니다 하지 그것을 잡기 , 파이썬 출력 오류 메시지IOError: [Errno 32] Broken pipe종료 코드와 스크립트를 종료1 -이 증상 영업 톱이다.

  • 대부분의 경우 이것은 도움이되는 것보다 방해가 되므로 기본 동작으로 되 돌리는 것이 바람직합니다 .

    • 은 Using signal모듈을 수 있습니다 만, 그에 명시된 바와 같이 akhan의 대답 ; signal.signal()처리 할 신호를 첫 번째 인수로, 핸들러를 두 번째 인수로받습니다. 특수 핸들러 값 SIG_DFL은 시스템의 기본 동작을 나타냅니다 .

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

다른 쪽 끝에서 닫힌 파이프에 쓰려고하면 "Broken Pipe"오류가 발생합니다. 당신이 보여준 코드는 파이프를 직접적으로 포함하지 않기 때문에, 나는 당신이 파이썬 인터프리터의 표준 출력을 다른 곳으로 리디렉션하기 위해 파이썬 외부에서 무언가를하고 있다고 생각합니다. 다음과 같은 스크립트를 실행하는 경우 발생할 수 있습니다.

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) 

실제로 위험합니다 (이미 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

그러나 이것만으로는 충분하지 않습니다. Python 3은 여전히 ​​다음과 같은 메시지를 인쇄 할 수 있습니다.

Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe

Unfortunately getting rid of that message is not straightforward, but I finally found http://bugs.python.org/issue11380 where Robert Collins suggests this workaround that I turned into a decorator you can wrap your main function with (yes, that's some crazy indentation):

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

This can also occur if the read end of the output from your script dies prematurely

ie open.py | otherCommand

if otherCommand exits and open.py tries to write to stdout

I had a bad gawk script that did this lovely to me.


I know this is not the "proper" way to do it, but if you are simply interested in getting rid of the error message, you could try this workaround:

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

Closes should be done in reverse order of the opens.

참고URL : https://stackoverflow.com/questions/14207708/ioerror-errno-32-broken-pipe-python

반응형