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


88

매우 간단한 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

@squiguy 라인 2 :print(f1.readlines())
JOHANNES_NYÅTT

2
두 번째 줄에서 두 개의 IO 작업이 발생합니다. 읽기 a.txt및 쓰기 stdout. 예외를 트리거하는 작업을 확인할 수 있도록 별도의 줄로 분할 해보십시오. 경우 stdout파이프이며, 읽기 끝이 폐쇄되어, 그는 설명 할 수 EPIPE오류입니다.
James Henstridge 2013 년

1
출력시이 오류를 재현 할 수 있으므로 (올바른 조건이 주어지면) print호출이 범인이라고 생각합니다 . @ JOHANNES_NYÅTT, Python 스크립트를 시작하는 방법을 명확히 할 수 있습니까? 표준 출력을 어딘가로 리디렉션하고 있습니까?
Blckknght 2013 년

2
:이 가능한 다음과 같은 질문의 중복 stackoverflow.com/questions/11423225/...

답변:


45

나는 문제를 재현하지 않았지만 아마도이 방법으로 해결할 수 있습니다. ( 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


7
이것은 좋은 프로그래밍 관행이지만 질문자가 얻는 깨진 파이프 오류와 관련이 없다고 생각합니다 ( print파일을 읽는 것이 아니라 호출 과 관련이 있음 ).
Blckknght 2013 년

@Blckknght 몇 가지 질문과 대체 방법을 추가했으며 저자의 피드백을 기다리고있었습니다. 문제가 열린 파일에서 인쇄 문으로 직접 대량의 데이터를 보내는 경우 위의 대안 중 하나가 문제를 해결할 수 있습니다.
Alex L

(-를 인쇄 한 후 전체 파일을로드 할 특별한 이유가없는 한 그것을 다른 방법을, 가장 간단한 솔루션은 종종 최고)
알렉스 L

1
이 문제를 해결하는 데있어 멋진 작업입니다! 이 답변을 당연시 할 수는 있지만 다른 답변 (및 내 자신의 접근 방식)이 귀하의 답변과 비교하여 어떻게 창백 해 졌는지 확인한 후에야 감사 할 수 있습니다.
Jesvin Jose

117

문제는 SIGPIPE 처리 때문입니다. 다음 코드를 사용하여이 문제를 해결할 수 있습니다.

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

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


13
방금 발견 한 것처럼 이것은 매우 위험합니다. 왜냐하면 소켓 (httplib 등)에서 SIGPIPE를 받으면 경고 나 오류없이 프로그램이 종료되기 때문입니다.
David Bennett

1
@DavidBennett, 나는 그 응용 프로그램에 따라 다르며 귀하의 목적에 맞는 대답이 옳다고 확신합니다. 사람들이 정보에 입각 한 결정을 내릴 수 있도록 여기 에는 훨씬 철저한 Q & A가 있습니다 . IMO, 명령 줄 도구의 경우 대부분의 경우 파이프 신호를 무시하는 것이 가장 좋습니다.
akhan

1
일시적으로 만 수행 할 수있는 방법이 있습니까?
Nate Glenn

2
@NateGlenn 기존 핸들러를 저장하고 나중에 복원 할 수 있습니다 .
akhan

3
사람들이 블로그 스팟 기사를 공식 문서 보다 더 나은 정보 출처로 간주하는 이유에 대해 누군가 제게 대답 할 수 있습니까 (힌트 : 링크를 열어 깨진 파이프 오류를 올바르게 수정하는 방법을 확인하십시오)? :)
Yurii Rabeshko

92

가져 알렉스 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) 
      

32

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

python foo.py | someothercommand

문제 someothercommand는 표준 입력에서 사용할 수있는 모든 것을 읽지 않고 종료 된다는 것 입니다. 이로 인해 (를 통한 print) 쓰기 가 어느 시점에서 실패합니다.

Linux 시스템에서 다음 명령을 사용하여 오류를 재현 할 수있었습니다.

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

less모든 입력 (1000 줄)을 스크롤하지 않고 페이저를 닫으면 Python IOError이보고 한대로 종료됩니다 .


10
예, 사실이지만 어떻게 수정합니까?
JOHANNES_NYÅTT

2
해결 방법을 알려주십시오.
JOHANNES_NYÅTT

1
@ JOHANNES_NYÅTT : 대부분의 Unix 계열 시스템에서 파이프가 제공하는 버퍼링으로 인해 작은 파일에서 작동 할 수 있습니다. 파일의 전체 내용을 버퍼에 쓸 수 있다면 다른 프로그램이 해당 데이터를 읽지 않아도 오류가 발생하지 않습니다. 그러나 쓰기가 차단되면 (버퍼가 가득 차서) 다른 프로그램이 종료 될 때 실패합니다. 다시 말하면 : 다른 명령은 무엇입니까? 파이썬 코드만으로는 더 이상 당신을 도울 수 없습니다 (잘못된 일을하는 부분이 아니기 때문입니다).
Blckknght 2013 년

1
머리에 배관 할 때이 문제가 발생했습니다. 출력 10 줄 후 예외입니다. 아주 논리적,하지만 여전히 예상치 못한 :)
앙드레 라즐로

4
@Blckknght : 일반적으로 좋은 정보,하지만 다시 " 수정 이 :와"를하고있어 일부 잘못된 것 "하십시오 SIGPIPE신호가 반드시 표시되지 않는 오류 상태를, 특히 일부 유닉스 유틸리티 head, 디자인에 의한, 정상 작동시 가까운 파이프 일찍, 그들이 필요한 만큼 많은 데이터를 읽었을 때
mklement0

20

사용하는 방법을 지적해야 할 의무가 있다고 생각합니다.

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

불행히도 그 메시지를 제거하는 것은 간단하지 않지만 마침내 http://bugs.python.org/issue11380을 찾았습니다. 여기서 Robert Collins는 내가 메인 함수를 래핑 할 수있는 데코레이터로 바꾼이 해결 방법을 제안합니다. 들여 쓰기):

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

2
이것은 나를 위해 그것을 고치는 것 같지 않았습니다.
Kyle Bridenstine

BrokenPipeError : supress_broken_pipe_msg 함수를 전달합니다
Rupen B

2

이것이 "적절한"방법이 아니라는 것을 알고 있지만 단순히 오류 메시지를 제거하는 데 관심이있는 경우 다음 해결 방법을 시도해 볼 수 있습니다.

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

2

여기에있는 최고 답변 ( if e.errno == errno.EPIPE:)은 저에게 실제로 효과가 없었습니다. 나는 얻었다 :

AttributeError: 'BrokenPipeError' object has no attribute 'EPIPE'

그러나 이것은 특정 쓰기에서 깨진 파이프를 무시하는 것뿐이라면 작동합니다. SIGPIPE를 트래핑하는 것보다 더 안전하다고 생각합니다.

try:
    # writing, flushing, whatever goes here
except BrokenPipeError:
    exit( 0 )

당신은 분명히 당신의 코드가 깨진 파이프에 부딪혔다면 당신의 코드가 정말로, 정말로 완료되었는지에 대한 결정을 내려야합니다.하지만 대부분의 목적에서 저는 그것이 보통 사실이라고 생각합니다. (파일 핸들을 닫는 것을 잊지 마십시오.)


1

스크립트 출력의 읽기 끝이 너무 일찍 종료 된 경우에도 발생할 수 있습니다.

즉, open.py | otherCommand

otherCommand가 종료되고 open.py가 stdout에 쓰려고하는 경우

나는 나에게 이렇게 사랑스러운 나쁜 gawk 스크립트를 가지고 있었다.


2
이 프로세스가 파이프에서 읽기에 대한 아니라 죽어 반드시 : 일부 유닉스 유틸리티, 특히 head, 디자인, 정상 작동 중에 그들이 많은 데이터로 읽은 후 가까운 파이프 초기으로 그들이 필요로했다. 대부분의 CLI는 기본 동작을 위해 시스템을 연기합니다. 읽기 프로세스를 조용히 종료하고 종료 코드를보고합니다 141(셸에서는 파이프 라인의 마지막 명령이 전체 종료 코드를 결정 하기 때문에 쉽게 알 수 없음 ). 불행히도 파이썬 의 기본 동작은 시끄럽게 죽는 것 입니다.
mklement0

-1

닫기는 열기의 역순으로 수행해야합니다.


4
그것은 일반적으로 좋은 습관이지만,하지 않는 것은 그 자체로 문제가 아니며 OP의 증상을 설명하지 않습니다.
mklement0
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.