नामित पाइप, फ़ाइल विवरणक और ईओएफ


10

दो विंडो, एक ही यूजर, बैश प्रॉम्प्ट के साथ। विंडो -1 प्रकार में:

$ mkfifo f; exec <f

तो बैश अब फाइल डिस्क्रिप्टर 0 से पढ़ने का प्रयास कर रहा है, जिसे नामांकित पाइप में मैप किया गया है f। विंडो -2 प्रकार में:

$ echo ls > f

अब विंडो -1 एक एलएस प्रिंट करता है और फिर शेल मर जाता है। क्यों?

अगला प्रयोग: खुली हुई खिड़की -1 के साथ फिर से exec <f। विंडो -2 प्रकार में:

$ exec 3>f
$ echo ls >&3

ऊपर की पहली पंक्ति के बाद, विंडो -1 जागता है और एक शीघ्र प्रिंट करता है। क्यों? ऊपर दूसरी पंक्ति के बाद, विंडो -1 lsआउटपुट को प्रिंट करता है और शेल जीवित रहता है। क्यों? वास्तव में, अब विंडो -2 में, echo ls > fविंडो -1 शेल को बंद नहीं करता है।

जवाब के लिए फ़ाइल -2 के विवरण के अस्तित्व के साथ करना होगा खिड़की -2 से नामित पाइप का संदर्भ देते हुए ?!


1
बाद exec <f, bashकरने का प्रयास नहीं कर रहा है पढ़ा से f, यह पहली करने के लिए प्रयास कर रहा है खोलने यह। open()कुछ पाइप को राइट मोड में एक और खुला (जिसके आधार पर पाइप instantiated किया जाएगा, और खोल यह से इनपुट पढ़ा जाएगा) कर रही प्रक्रिया नहीं होने तक, नहीं लौटेगा।
स्टीफन चेज़लस

उत्कृष्ट बिंदु, @ स्टीफनचेज़लस। यह होना चाहिए, एक बार exec 3>fचलाए जाने के बाद, पहला शेल फिर एक संकेत देता है। (माइनर बिंदु, आप "में मतलब था लिखने अपनी टिप्पणी में मोड"?)
Fixee

1
हाँ क्षमा करें। 5 मिनट की समय सीमा से ठीक पहले अब संपादित किया गया
स्टीफन चेज़लस

जवाबों:


12

यह फाइल डिस्क्रिप्टर के समापन के साथ करना है ।

अपने पहले उदाहरण में, echoइसकी मानक आउटपुट स्ट्रीम को लिखता है जिसे शेल इसे से कनेक्ट करने के लिए खोलता है f, और जब यह समाप्त हो जाता है, तो इसका डिस्क्रिप्टर बंद होता है (शेल द्वारा)। प्राप्त करने के अंत में, शेल, जो अपने मानक इनपुट स्ट्रीम से इनपुट पढ़ता है (जुड़ा हुआ है f) पढ़ता है ls, चलाता है lsऔर उसके मानक इनपुट पर फ़ाइल की समाप्ति स्थिति के कारण समाप्त हो जाता है।

फ़ाइल की समाप्ति स्थिति इसलिए होती है क्योंकि नामित पाइप (इस उदाहरण में केवल एक) के सभी लेखकों ने पाइप के अपने अंत को बंद कर दिया है।

अपने दूसरे उदाहरण में, exec 3>fलिखने के लिए फ़ाइल डिस्क्रिप्टर 3 खोलता है f, फिर उसे echoलिखता lsहै। यह शेल है कि अब फाइल डिस्क्रिप्टर खोला गया है, echoकमांड नहीं । वर्णनकर्ता तब तक खुला रहता है जब तक आप ऐसा नहीं करते exec 3>&-। प्राप्त करने के अंत में, शेल, जो अपने मानक इनपुट स्ट्रीम (कनेक्टेड f) से इनपुट पढ़ता है ls, चलाता है lsऔर फिर अधिक इनपुट की प्रतीक्षा करता है (चूंकि स्ट्रीम अभी भी खुली है)।

धारा खुली रहती है क्योंकि सभी लेखकों ने इसे (शेल, थ्रू exec 3>fऔर echo) पाइप के अंत में बंद नहीं किया है ( exec 3>fयह अभी भी प्रभाव में है)।


मैंने echoऊपर के बारे में लिखा है जैसे कि यह एक बाहरी आदेश था। यह सबसे अधिक संभावना है कि शेल में बनाया गया है। प्रभाव फिर भी वही है।


6

इसके लिए बहुत कुछ नहीं है: जब पाइप के लिए कोई लेखक नहीं होते हैं, तो यह पाठकों के लिए बंद दिखता है, अर्थात जब पढ़ा जाता है और खोले जाने पर ईओएफ लौटता है।

लिनक्स मैन पेज से ( pipe(7), लेकिन यह भी देखें fifo(7)):

यदि किसी पाइप के लिखने के अंत का जिक्र करने वाले सभी फ़ाइल विवरणकों को बंद कर दिया गया है, तो read(2)पाइप से एक प्रयास के अंत में फाइल दिखाई read(2)देगी ( 0 लौटेगी)।

लिखने के अंत को बंद करने के अंत में क्या निहित है echo ls >f, और जैसा कि आप कहते हैं, दूसरे मामले में, फ़ाइल विवरणक को खुला रखा जाता है।


जावा (और अन्य OO भाषाओं) में संदर्भ संख्या के अनुरूप तरह का लगता है! हालांकि समझ में आता है।
फिक्सि

2

@Kusalananda और @ikachachu से दो जवाब पढ़ने के बाद, मुझे लगता है कि मैं समझता हूं। विंडो -1 में, शेल किसी चीज़ का इंतज़ार कर रहा है ताकि दोनों पाइप के राइट एंड को खोल सकें और फिर उसे बंद कर दें। राइट एंड खोलने के बाद, विंडो -1 में शेल प्रॉम्प्ट को प्रिंट करता है। राइट एंड बंद होने के बाद, शेल EOF हो जाता है और मर जाता है।

विंडो -2 की तरफ हमारे प्रश्न में वर्णित दो स्थितियाँ हैं: पहली स्थिति में echo ls > f, कोई फाइल डिस्क्रिप्टर 3 नहीं है, इसलिए हमारे पास echoस्पॉनिंग है, और इसके stdinऔर stdoutइस तरह दिखते हैं:

0 --> tty
1 --> f

फिर echoसमाप्त होता है और शेल दोनों विवरणों को बंद कर देता है। चूंकि फाइल डिस्क्रिप्टर 1 बंद है और संदर्भ है f, इसलिए राइट ऑफ fबंद है और यह विंडो -1 के लिए ईओएफ का कारण बनता है।

दूसरी स्थिति में, हम exec 3>fअपने शेल में चलते हैं, जिससे शेल इस वातावरण को ग्रहण करता है:

bash:
0 --> tty
1 --> tty
2 --> tty
3 --> f

अब हम चलाते हैं echo ls >& 3और शेल echoनिम्नानुसार फ़ाइल डिस्क्रिप्टर आवंटित करते हैं:

echo:
0 --> tty
1 --> f     # because 3 points to f
2 --> tty

फिर खोल ऊपर सहित तीन विवरणों को बंद कर देता है f, लेकिन fअभी भी शेल से ही इसका संदर्भ है। यह महत्वपूर्ण अंतर है। विवरणक 3 exec 3>&-को बंद करने से अंतिम खुला संदर्भ बंद हो जाएगा और विंडो -1 के लिए ईओएफ का कारण होगा, जैसा कि @ कुसलानंद ने कहा।


यह एक अच्छा उदाहरण है कि आपको पहले तीन फ़ाइल डिस्क्रिप्टर को अकेले क्यों छोड़ना चाहिए जब तक कि उन्हें संशोधित करने के लिए अच्छा डिज़ाइन कारण न हो। जब आपने डिस्क्रिप्टर (1) का उपयोग किया, जो दूसरे शेल में इनपुट डिस्क्रिप्टर (0) होने के कारण समाप्त हो गया, तो आपने न केवल पाइप को बंद कर दिया (और आप उस विशेष डेटा स्ट्रीम के साथ क्या कर रहे थे), बल्कि इनपुट को दूसरे के लिए भी बंद कर दिया। शेल जिसके कारण यह समाप्त हो गया। यह ठीक है, लेकिन केवल अगर आप इसे उद्देश्य से कर रहे हैं। उच्च संख्या वाली फ़ाइल डिस्क्रिप्टर का उपयोग करने से साइड इफेक्ट्स से बचा जाता है क्योंकि कुछ भी उन्हें किसी विशेष स्थिति में या यहां तक ​​कि परिभाषित होने की उम्मीद नहीं करता है।
जो

ईमानदार होने के लिए, मुझे यकीन नहीं है कि मैं उस टिप्पणी में क्या कहना चाह रहा था, मैं इसे हटा दूंगा।
स्टीफन चेजलस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.