बैश पाइपलाइनों पर `हां` का उपयोग क्यों नहीं करता है * अनंत छोरों का कारण नहीं है?


16

इसके दस्तावेज़ीकरण के अनुसार, बैश का इंतजार तब तक किया जाता है जब तक कि पाइप लाइन की सभी कमांड जारी रखने से पहले समाप्त नहीं हो जाती

मूल्य वापस करने से पहले शेल पाइपलाइन में सभी कमांड का इंतजार करता है।

तो कमांड yes | trueतुरंत खत्म क्यों करता है ? yesलूप हमेशा के लिए नहीं होना चाहिए और पाइप लाइन को कभी वापस नहीं करना चाहिए ?


और एक शकुन: पोसिक्स कल्पना के अनुसार , शेल पाइपलाइन अंतिम कमांड के खत्म होने के बाद या तो वापस लौटने का विकल्प चुन सकते हैं या तब तक इंतजार कर सकते हैं जब तक कि सभी कमांड खत्म न हो जाएं। क्या आम गोले इस अर्थ में अलग व्यवहार करते हैं? क्या ऐसे कोई गोले हैं जहाँ yes | trueहमेशा के लिए लूप होगा?


yes | tee >(true) >/dev/nullजैसा कि आप उम्मीद करते हैं, btw, जैसा teeकि सभी लेखकों के मरने तक जारी रहेगा, इसलिए trueबाहर निकलने से यह पूरी तरह से बाधित नहीं होगा।
चार्ल्स डफी

1
trueमूल रूप से एक {return 0;}कार्यक्रम है, इसलिए मैं इसे लंबे समय तक चलने की उम्मीद नहीं करूंगा, हमेशा के लिए अकेले रहने दें।
दिमित्री ग्रिगोरीव

जवाबों:


33

जब trueबाहर निकलता है, तो पाइप का रीड साइड बंद हो जाता है, लेकिन yesराइट टू साइड लिखने की कोशिश जारी रखता है। इस स्थिति को "टूटी हुई पाइप" कहा जाता है, और यह कर्नेल को SIGPIPEसिग्नल भेजने का कारण बनता है yes। चूंकि yesइस सिग्नल के बारे में कुछ खास नहीं है, इसलिए इसे मार दिया जाएगा। यदि उसने सिग्नल को नजरअंदाज किया, तो writeत्रुटि कोड के साथ उसका कॉल विफल हो जाएगा EPIPE। ऐसे कार्यक्रम जो नोटिस करने EPIPEऔर लिखना बंद करने के लिए तैयार किए जाने हैं , या वे एक अनंत लूप में जाएंगे।

यदि आप strace yes | true1 करते हैं तो आप दोनों संभावनाओं के लिए कर्नेल की तैयारी देख सकते हैं:

write(1, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 4096) = -1 EPIPE (Broken pipe)
--- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=17556, si_uid=1000} ---
+++ killed by SIGPIPE +++

straceडिबगर एपीआई के माध्यम से घटनाओं को देख रहा है, जो पहले इसे सिस्टम कॉल को एक त्रुटि के साथ लौटने के बारे में बताता है, और फिर सिग्नल के बारे में। से yesकी परिप्रेक्ष्य, हालांकि, संकेत पहले होता है। (तकनीकी रूप से, सिग्नल को कर्नेल रिटर्न के बाद उपयोगकर्ता स्थान पर पहुंचाया जाता है, लेकिन इससे पहले कि कोई और मशीन निर्देश निष्पादित हो, इसलिए writeC लाइब्रेरी में "आवरण" फ़ंक्शन को सेट errnoकरने और एप्लिकेशन पर लौटने का मौका नहीं मिलता है ।)


1 अफसोस की बात है, straceलिनक्स विशिष्ट है। अधिकांश आधुनिक यूनिक्स में कुछ कमांड होती है जो कुछ ऐसा ही करती है, लेकिन इसका अक्सर एक अलग नाम होता है, यह संभवतः syscall तर्कों को पूरी तरह से डिकोड नहीं करता है, और कभी-कभी यह केवल रूट के लिए काम करता है।


3
@ हगोमग उस मामले में, पाइप पूरी तरह से अप्रासंगिक है।
मूरू

3
@hugomg क्योंकि कुछ भी yesपाइप से जुड़ा नहीं है।
मूरू

4
यह सच है, कि प्रलेखित व्यवहार का एक प्रदर्शन है "जब तक पाइपलाइन समाप्त करने से पहले सभी कमांड खत्म नहीं हो जाते तब तक प्रतीक्षा करें"। यह सिर्फ yesSIGPIPE प्राप्त करने से रोकता है, क्योंकि FD जो इसे लिख रहा है वह एक पाइप से जुड़ा नहीं है।
टॉम हंट

2
@ हगोमग, यह हमेशा के लिए उसी तरह yes >/dev/nullसे लूपिंग है जो हमेशा के लिए लूपिंग है। यह उन सभी पाइपलाइनों के बारे में कुछ भी प्रदर्शित नहीं करता है जो सरल आदेशों के बारे में भी सच नहीं है (जैसे कि प्रतीक्षा-समाप्ति व्यवहार टॉम के बिंदुओं के साथ-साथ सरल आदेशों का भी सच है)।
चार्ल्स डफी

2
@zwol: मुझे लगता है कि हम अपनी शर्तों का उपयोग यहां कुछ अलग अर्थों के साथ कर रहे हैं, या कुछ अलग-अलग दृष्टिकोणों से चीजों के बारे में सोच रहे हैं ... लेकिन किसी भी स्थिति में, write()(libc में फ़ंक्शन) वापस नहीं आता (इसके बाद पीसी पर नियंत्रण स्थानांतरित करें) सिग्नल हैंडलर चला गया है, लेकिन चूंकि सिग्नल हैंडलर प्रोग्राम को समाप्त कर देता है, इसलिए नियंत्रण कभी स्थानांतरित नहीं होता है और इसलिए write()कभी वापस नहीं आता है। हां, यह कर्नेल में कुछ xxx_write()फंक्शन रिटर्न के द्वारा कार्यान्वित किया गया है -EPIPE, लेकिन हम एक उपयोगकर्ता-स्पेस प्रोग्राम को डिबग कर रहे हैं और उस पर अबाधित है।
डिट्रीच एप्प

5

क्या कोई गोले हैं जहाँ हाँ | सच हमेशा के लिए पाश जाएगा?

पूरी तरह से, चूंकि yesकमांड पाइप का उपयोग कर रहा है, और पाइप के टूटने पर यह विफल हो जाएगा। sleepदूसरी ओर, पाइप का उपयोग नहीं करता है, इसलिए:

sleep 100000000 | true

कम से कम 100000000 सेकंड तक चलेगा।


2
सभी आधुनिक गोले पर सावधान रहें जो एक पाइप में अंतिम (सबसे दाएं) अंतर्निहित कमांड के लिए कांटा नहीं करते हैं और जहां trueएक बिलिन है। इस के हाल के संस्करणों पर लागू होता है Bourne Shell, ksh93, zsh। यदि आप ^Zइस तरह की कमांड चला रहे हैं, तो यह नींद को रोक देगा और शेल बाहरी मदद के बिना कभी भी ठीक नहीं हो पाएगा।
श्वेत

3
zsh 4.3.4 (i386-pc-Solaris2.11) यहां, इसलिए ऐसा लगता है कि इसे हाल ही में संशोधित किया गया था। दिलचस्प विचार, मुझे एक नज़र रखने की आवश्यकता होगी कि क्या मैं बॉर्न शेल के लिए एक समान फिक्स लागू कर सकता हूं। अभी भी एक सवाल है कि यह कैसे काम करता है, और बॉर्न शेल के रूप में किस tty प्रक्रिया समूह का उपयोग किया जाता है तथ्य यह है कि सबसे कठोर कमान एक बिल्डिन है जिसे नींद के लिए प्रक्रिया समूह के बाद पहले से ही हमेशा के लिए सेट किया गया था।
श्वेत

2
@CharlesDuffy जो मुझे समझ में आया है, विद्वानों ने श के एक संस्करण को बनाए रखा है, जिसमें वह आधुनिक गोले से सुधारों का समर्थन करता है। वह इसके बारे में यहां पोस्ट कर रहा है, कहीं।
मूरू

3
उत्तराधिकारी अभिलेखागार में बॉर्न शेल को ~ 2007 तक बनाए रखा गया था, लेकिन कभी भी इसे पूरी तरह से पोर्टेबल नहीं बनाया गया था क्योंकि इसमें अभी भी कॉल शामिल नहीं हैं sbrk()। एक पोर्टेबल और बनाए रखा संस्करण है में schily उपकरण बंडल और @Charles डफी पहले से ही जानकारी के लिए ;-) एक स्थान की खोज की
schily

2
@ बॉर्न शेल के लिए मेरे द्वारा बैक किए गए कई सुविधाओं में से कई मेरे bsh(वर्बटोस से बर्थोल्ड शेल, यूएनओएस का एक वर्चुअल मेमोरी वर्धित संस्करण - पहला यूनिक्स क्लोन) हैं। 1984 और 1985 में Bsh को कई csh फीचर्स मिले लेकिन UNOS से अलियास तंत्र 1980 में पहले से ही csh से बेहतर था। अन्य नई बॉर्न शैल विशेषताएं पोसिक्स से हैं, इसे पोसिक्स अनुपालन का दृष्टिकोण करने देती हैं।
18
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.