IOError: [एर्रनो 32] टूटा हुआ पाइप: पायथन


88

मेरे पास एक बहुत ही सरल पायथन 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।

मैं आउटपुट को रीडायरेक्ट कर रहा हूं, इसलिए यदि उपरोक्त स्क्रिप्ट का नाम "ओपनहेड" रखा गया है, तो मेरी रनिंग कमांड होगी:

open.py | othercommand

@squiguy लाइन 2:print(f1.readlines())
JOHANNES_NYTTT

2
आपको लाइन 2 पर होने वाले दो IO ऑपरेशन मिले हैं: एक से पढ़ा a.txtऔर एक को stdout। शायद अलग-अलग लाइनों पर उन्हें विभाजित करने का प्रयास करें ताकि आप देख सकें कि कौन सा ऑपरेशन अपवाद को ट्रिगर करता है। यदि stdoutएक पाइप है और रीड एंड बंद हो गया है, तो वह EPIPEत्रुटि के लिए जिम्मेदार हो सकता है ।
जेम्स हेनरिज

1
मैं आउटपुट पर इस त्रुटि को पुन: उत्पन्न कर सकता हूं (सही शर्तों को देखते हुए), इसलिए मुझे संदेह है कि printकॉल अपराधी है। @ JOHANNES_NYÅTT, क्या आप स्पष्ट कर सकते हैं कि आप अपनी पायथन लिपि को कैसे लॉन्च कर रहे हैं? क्या आप कहीं मानक उत्पादन को पुनर्निर्देशित कर रहे हैं?
ब्लैंकनाथ

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पाइप से पढ़ने से पहले यह बहुत बड़ा हो जाता है - /unix/11946/how-big-is-the-pipe-buffer


7
हालांकि यह अच्छा प्रोग्रामिंग अभ्यास है, मुझे नहीं लगता कि प्रश्नकर्ता को टूटी हुई पाइप त्रुटि के साथ इसका कोई लेना देना है (जो शायद printकॉल के साथ करना है , फाइलों को पढ़ने के साथ नहीं)।
ब्लैंकनाथ

@ ब्लेकन्चट मैंने कुछ सवाल और वैकल्पिक तरीके जोड़े और लेखक से कुछ प्रतिक्रिया की उम्मीद कर रहा था। यदि समस्या एक खुली फ़ाइल से प्रिंट स्टेटमेंट में बड़ी मात्रा में डेटा भेज रही है तो शायद ऊपर दिए गए विकल्पों में से एक इसे ठीक कर देगा।
एलेक्स एल

(सबसे सरल समाधान अक्सर सबसे अच्छे होते हैं - जब तक कि किसी पूरी फ़ाइल को लोड करने के लिए कोई विशेष कारण न हो, तब इसे प्रिंट करें, इसे अलग तरीके से करें)
एलेक्स एल

1
इस समस्या निवारण में बहुत बढ़िया काम! यद्यपि मैं इस उत्तर को प्रदान कर सकता था, मैं केवल इस बात की सराहना कर सकता था कि आपके उत्तर की तुलना में अन्य उत्तर (और मेरे अपने दृष्टिकोण) को कैसे देखा जाए।
जेसविन जोस

117

SIGPIPE हैंडलिंग के कारण समस्या है। आप निम्न कोड का उपयोग करके इस समस्या को हल कर सकते हैं:

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

इस समाधान पर पृष्ठभूमि के लिए यहां देखेंयहां बेहतर जवाब ।


13
यह बहुत खतरनाक है, जैसा कि मैंने अभी पता लगाया है, क्योंकि यदि आपको कभी भी सॉकेट (रिशेप्लिब या जो भी हो) पर SIGPIPE मिलता है, तो आपका प्रोग्राम बिना किसी चेतावनी या त्रुटि के बाहर निकल जाएगा।
डेविड बेनेट

1
@DavidBennett, मुझे यकीन है कि इसका आवेदन निर्भर है और आपके उद्देश्यों के लिए स्वीकृत उत्तर सही है। लोगों द्वारा जाने और सूचित निर्णय लेने के लिए यहां बहुत अधिक प्रश्नोत्तर है । IMO, कमांड लाइन टूल्स के लिए, ज्यादातर मामलों में पाइप सिग्नल को अनदेखा करने के लिए संभवत: सबसे अच्छा है।
अक्खन

1
केवल अस्थायी रूप से ऐसा करने का कोई तरीका?
नैट ग्लेन

2
@NateGlenn आप मौजूदा हैंडलर को बचा सकते हैं और इसे बाद में पुनर्स्थापित कर सकते हैं।
अखन

3
क्या कोई मुझे जवाब दे सकता है कि लोग आधिकारिक दस्तावेज की तुलना में ब्लॉगस्पॉट लेख को सच्चाई का एक बेहतर स्रोत क्यों मान रहे हैं (संकेत: टूटी हुई पाइप त्रुटि को ठीक से कैसे ठीक करें यह देखने के लिए लिंक खोलें)? :)
यूरी राबेशको

92

लाने के लिए एलेक्स एल के मददगार जवाब , Akhan के मददगार जवाब , और Blckknght के मददगार जवाब कुछ अतिरिक्त जानकारी के साथ एक साथ:

  • SIGPIPEजब पाइप (अब) से पढ़ने की कोई प्रक्रिया नहीं होती है, तो मानक यूनिक्स सिग्नल को पाइप से लिखने की प्रक्रिया में भेजा जाता है ।

    • यह जरूरी नहीं कि एक त्रुटि स्थिति हो; कुछ यूनिक्स उपयोगिताओं जैसे कि head डिजाइन से समय से पहले पाइप से पढ़ना बंद हो जाता है, एक बार जब वे पर्याप्त डेटा प्राप्त कर लेते हैं।
  • डिफ़ॉल्ट रूप से - अर्थात, यदि लेखन प्रक्रिया स्पष्ट रूप से नहीं फंसती है SIGPIPE - लेखन प्रक्रिया को बस समाप्त कर दिया जाता है , और इसके निकास कोड को सेट किया जाता है141 , जिसे 128(सामान्य रूप से संकेत द्वारा संकेत को समाप्त करने के लिए) + 13( SIGPIPE's विशिष्ट संकेत संख्या ) के रूप में गणना की जाती है। ।

  • डिजाइन के अनुसार, हालांकि, पायथन खुद फंस जाता हैSIGPIPE और मूल्य के साथ इसे पायथनIOError उदाहरण में बदल देता है , ताकि पायथन स्क्रिप्ट इसे पकड़ सके, अगर यह ऐसा चुनता है - तो इसे करने के लिए एलेक्स एल का जवाब देखें ।errnoerrno.EPIPE

  • यदि पायथन स्क्रिप्ट इसे नहीं पकड़ती है , तो पायथन त्रुटि संदेश को आउटपुट IOError: [Errno 32] Broken pipeकरता है और स्क्रिप्ट को निकास कोड के साथ समाप्त करता है1 - यह वह लक्षण है जिसे ओपी ने देखा है।

  • कई मामलों में यह सहायक की तुलना में अधिक विघटनकारी है , इसलिए डिफ़ॉल्ट व्यवहार को प्रभावित करना वांछनीय है :

    • signalमॉड्यूल का उपयोग करने की अनुमति देता है बस, जैसा कि अखन के जवाब में कहा गया है ; signal.signal()1 तर्क और 2 के रूप में एक हैंडलर के रूप में संभालने के लिए एक संकेत लेता है; विशेष हैंडलर मान SIG_DFLसिस्टम के डिफ़ॉल्ट व्यवहार का प्रतिनिधित्व करता है :

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

32

"टूटी हुई पाइप" त्रुटि तब होती है जब आप उस पाइप पर लिखने की कोशिश करते हैं जिसे दूसरे छोर पर बंद कर दिया गया है। चूंकि आपने जो कोड दिखाया है, उसमें सीधे कोई पाइप शामिल नहीं है, मुझे संदेह है कि आप पायथन इंटरप्रेटर के मानक आउटपुट को कहीं और रीडायरेक्ट करने के लिए पायथन के बाहर कुछ कर रहे हैं। यदि आप इस तरह से स्क्रिप्ट चला रहे हैं तो ऐसा हो सकता है:

python foo.py | someothercommand

आपके पास जो समस्या है वह someothercommandयह है कि इसके मानक इनपुट पर उपलब्ध सब कुछ पढ़े बिना ही बाहर निकल रहे हैं। यह आपके लेखन (के माध्यम से print) किसी बिंदु पर विफल होने का कारण बनता है ।

मैं लिनक्स सिस्टम पर निम्न कमांड के साथ त्रुटि को पुन: उत्पन्न करने में सक्षम था:

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

यदि मैं lessअपने सभी इनपुट (1000 लाइनों) के माध्यम से स्क्रॉल किए बिना पेजर को बंद कर देता हूं , तो पायथन उसी के साथ बाहर निकलता है जैसा IOErrorआपने रिपोर्ट किया है।


10
हां, यह सच है, लेकिन मैं इसे कैसे ठीक करूं?
जोहान्स_नियम

2
कृपया मुझे बताएं कि इसे कैसे ठीक किया जाए।
जोहान्स_नियम

1
@ JOHANNES_NYÅTT: अधिकांश यूनिक्स जैसी प्रणालियों पर पाइप द्वारा प्रदान की गई बफरिंग के कारण यह छोटी फाइलों के लिए काम कर सकती है। यदि आप फ़ाइलों की पूरी सामग्री को बफर में लिख सकते हैं, तो यह एक त्रुटि नहीं उठाता है यदि अन्य प्रोग्राम उस डेटा को कभी नहीं पढ़ता है। हालाँकि, यदि लेखन ब्लॉक (क्योंकि बफ़र पूर्ण है), तो यह विफल हो जाएगा जब अन्य प्रोग्राम बंद हो जाता है। फिर से कहने के लिए: अन्य कमांड क्या है? हम केवल पायथन कोड के साथ आपकी कोई मदद नहीं कर सकते (क्योंकि यह वह हिस्सा नहीं है जो गलत काम कर रहा है)।
ब्लैंकनाथ

1
मुझे यह समस्या तब हुई जब सिर को पाइप करते हुए ... आउटपुट के दस लाइनों के बाद अपवाद। काफी तार्किक है, लेकिन अभी भी अप्रत्याशित :)
एंड्रे लास्ज़लो

4
@ ब्लेकनाथ: सामान्य रूप से अच्छी जानकारी, लेकिन फिर से "उसे ठीक करें : और" वह हिस्सा जो गलत काम कर रहा है ": एक SIGPIPEसंकेत जरूरी नहीं कि एक त्रुटि स्थिति का संकेत दे ; कुछ यूनिक्स उपयोगिताओं, विशेष रूप से head, डिजाइन के दौरान, सामान्य ऑपरेशन के दौरान पाइप को बंद करें जल्दी, के रूप में एक बार वे ज्यादा डेटा के रूप में पढ़ा है वे की जरूरत है।
mklement0

20

मुझे लगता है कि विधि का उपयोग करने के लिए बाध्य लगता है

signal(SIGPIPE, SIG_DFL) 

वास्तव में खतरनाक है (जैसा कि पहले ही डेविड बेनेट द्वारा टिप्पणियों में सुझाया गया है) और मेरे मामले में प्लेटफ़ॉर्म-निर्भर मज़ेदार व्यवसाय का नेतृत्व किया गया था जब multiprocessing.Manager(क्योंकि मानक पुस्तकालय ब्रोकनपाइप पर निर्भर करता है कई स्थानों पर उठाया जा रहा है)। एक लंबी और दर्दनाक कहानी को छोटा करने के लिए, मैंने इसे कैसे तय किया:

सबसे पहले, आपको IOError(अजगर 2) या BrokenPipeError(पायथन 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

हालाँकि, यह पर्याप्त नहीं है। अजगर 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

2
यह मेरे लिए इसे ठीक नहीं लगता था।
काइल ब्रिडेनस्टाइन

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

यह तब भी हो सकता है यदि आपकी स्क्रिप्ट से आउटपुट का पढ़ा हुआ अंत समय से पहले मर जाता है

यानी ओपनडैम | otherCommand

यदि अन्यकमांड से बाहर निकलता है और ओपन-वर्ड स्टैडआउट में लिखने की कोशिश करता है

मेरे पास एक बुरी गॉक स्क्रिप्ट थी जो मुझे बहुत प्यारी लगी।


2
यह प्रक्रिया पाइप से पढ़ने के बारे में नहीं है मर रहा है , जरूरी: कुछ यूनिक्स उपयोगिताओं, विशेष रूप से head, डिजाइन द्वारा, सामान्य ऑपरेशन के दौरान करीब पाइप जल्दी, के रूप में एक बार वे ज्यादा डेटा के रूप में पढ़ा है वे की जरूरत है। अधिकांश सीएलआई केवल सिस्टम को उसके डिफ़ॉल्ट व्यवहार के लिए टाल देते हैं: चुपचाप पढ़ने की प्रक्रिया को समाप्त करना और निकास कोड को रिपोर्ट करना 141(जो कि एक शेल में, आसानी से स्पष्ट नहीं है, क्योंकि एक पाइपलाइन की अंतिम कमांड समग्र निकास कोड को निर्धारित करती है)। पायथन का डिफ़ॉल्ट व्यवहार, दुर्भाग्य से, नीरवता से मरना है ।
mklement0

-1

क्लोज के रिवर्स ऑर्डर में क्लोज किया जाना चाहिए।


4
जबकि यह सामान्य रूप से अच्छा अभ्यास है, नहीं करना अपने आप में एक समस्या नहीं है और ओपी के लक्षणों को स्पष्ट नहीं करता है।
mklement0
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.