अगर ईओएफ को बिल्ली के माध्यम से पाइप नहीं किया जाता है, तो जीआरईपी आउटपुट नहीं करता है


19

इस न्यूनतम उदाहरण को देखते हुए

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; )

यह आउटपुट LINE 1और फिर, एक सेकंड के बाद, आउटपुट LINE 2, के रूप में की उम्मीद


अगर हम इसे पाइप करते हैं grep LINE

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE

व्यवहार पिछले मामले में जैसा अपेक्षित था वैसा ही है


यदि, वैकल्पिक रूप से, हम इसे पाइप करते हैं cat

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | cat

व्यवहार फिर से वही है, जैसा अपेक्षित था


हालाँकि , यदि हम पाइप करते हैं grep LINE, और फिर cat,

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep LINE | cat

एक सेकंड पास होने तक कोई आउटपुट नहीं है, और आउटपुट पर दोनों लाइनें तुरंत दिखाई देती हैं, जिसकी मुझे उम्मीद नहीं थी


ऐसा क्यों हो रहा है और मैं पहले तीन आदेशों के समान व्यवहार करने के लिए अंतिम संस्करण कैसे बना सकता हूं?


catफ़ाइलों को सम्‍मिलित करता है। आप पाइपिंग करके क्या करने की कोशिश कर रहे हैं cat?
डगलस हेल्ड

15
@DouglasHeld जब तर्कों के बिना बुलाया जाता है, तो catबस पढ़ता है stdinऔर इसमें आउटपुट देता है stdout। बेशक, मैं इस प्रश्न के साथ बहुत सारे जटिल सामानों के साथ आया था echoऔर cat, लेकिन ये बहुत अप्रासंगिक हो गए, क्योंकि समस्या बहुत सरल उदाहरणों के साथ दिखाई देती है।
०१:११ बजे

3
@ डगलसहेल्ड: बिल्ली को पीटना अक्सर एक टर्मिनल नहीं होने के लिए स्टडआउट के लिए उपयोगी होता है। उदाहरण के लिए, रंगीन आउटपुट का उपयोग न करने के लिए कई कमांड प्राप्त करने का यह एक आसान तरीका है।
व्रजगिन

मैं कसम खाता हूं कि स्टैक ओवरफ्लो पर एक और सवाल का दोहराव है !
IBug

@wchargin आपको बहुत-बहुत धन्यवाद, आपने मुझे पॉज़िक्स के बारे में कुछ नया सिखाया है जो मुझे कभी नहीं पता था।
डगलस हेल्ड

जवाबों:


38

जब (कम से कम GNU) grepआउटपुट टर्मिनल नहीं होता है, तो इसका आउटपुट बफ़र करता है, जो कि आपके द्वारा देखे जा रहे व्यवहार का कारण बनता है। आप इसे GNU grepके --line-bufferedविकल्प का उपयोग करके अक्षम कर सकते हैं :

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | grep --line-buffered LINE | cat

या stdbufउपयोगिता:

( echo "LINE 1" ; sleep 1 ; echo "LINE 2" ; ) | stdbuf -oL grep LINE | cat

इस विषय पर पाइप में बफरिंग बंद करें


26

सरलीकृत स्पष्टीकरण

कई उपयोगिताओं की तरह, यह एक कार्यक्रम के लिए कुछ अजीब नहीं है, लाइन बफर होने और पूरी तरह से बफरgrep होने के बीच अपने मानक उत्पादन को बदलता है । पूर्व के मामले में, C लाइब्रेरी बफ़र्स मेमोरी में डेटा तब तक आउटपुट करता है जब तक कि उन डेटा को पकड़ने वाले बफ़र को भर नहीं दिया जाता है या इसमें एक लाइनफ़ीड कैरेक्टर जोड़ दिया जाता है (या प्रोग्राम साफ़-सुथरा समाप्त हो जाता है), जिसके लिए वह वास्तव में बफर कंटेंट लिखने के लिए कॉल करता है। बाद के मामले में, केवल इन-मेमोरी बफर पूर्ण हो रहा है (या सफाई से समाप्त होने वाला प्रोग्राम) ट्रिगर होता है ।write()write()

अधिक विस्तृत विवरण

यह अच्छी तरह से जाना जाता है, लेकिन थोड़ा गलत है, स्पष्टीकरण। वास्तव में, मानक उत्पादन लाइन बफर नहीं है, लेकिन GNU C लाइब्रेरी और BSD C लाइब्रेरी में स्मार्ट बफर है। मानक इनपुट को पढ़ने के दौरान मानक आउटपुट को भी प्रवाहित किया जाता है, इसकी इन-मेमोरी बफर (पूर्व-पढ़े गए इनपुट) और सी लाइब्रेरी को कुछ और इनपुट लाने के लिए कॉल करना पड़ता है और यह एक नई लाइन की शुरुआत को पढ़ रहा है। (इसका एक कारण गतिरोध को रोकना है जब एक अन्य कार्यक्रम एक फिल्टर के दोनों सिरों से जुड़ता है और लाइन-बाय-लाइन को संचालित करने में सक्षम होने की उम्मीद करता है, फ़िल्टर से लिखने और इसे पढ़ने के बीच बारी-बारी से; जीएनयू में "कॉप्रोसेस" की तरह) उदाहरण के लिए।)read()awk

C पुस्तकालय प्रभाव

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

पूर्ण बफरिंग को अक्षम करने के लिए वर्कअराउंड

कुछ यूटिलिटीज जैसे grepidiosyncratic विकल्प हैं जैसे --line-bufferedकि इस निर्णय को बदलते हैं, जिसे आप देख सकते हैं कि गलत नाम है। लेकिन फ़िल्टर प्रोग्रामों का एक छोटा सा छोटा हिस्सा जो वास्तव में उपयोग कर सकता है, उसके पास ऐसा विकल्प हो सकता है।

आमतौर पर, कोई भी ऐसे उपकरण का उपयोग कर सकता है जो सी लाइब्रेरी के विशिष्ट इंटर्नल में खोदते हैं और अपने निर्णय लेने में बदलाव करते हैं (जिसमें सुरक्षा समस्याएं हैं यदि प्रोग्राम को बदल दिया जाए तो सेट-यूआईडी है, और विशेष रूप से सी लाइब्रेरी के लिए भी विशिष्ट हैं, और वास्तव में हैं कार्यक्रमों में लिखित या सी भाषा के शीर्ष पर स्तरित), या इस तरह के रूप उपकरण के लिए विशिष्ट ptybandageहै कि नहीं कार्यक्रम के आंतरिक भागों को बदल कर एक छद्म टर्मिनल मानक आउटपुट के रूप में निर्णय के रूप में "इंटरेक्टिव" बाहर आता है तो यह है कि बस लगाना, करने के लिए इसे प्रभावित करो।

आगे की पढाई


1
यदि वाक्यांश "लाइन बफ़र किया गया" एक मिथ्या नाम है, तो यह वास्तव में गलती नहीं है grep, लेकिन अंतर्निहित पुस्तकालय कॉल, setbuf/setvbuf । मुझे सी मानक के लिए एक विश्वसनीय ऑनलाइन संदर्भ का पता नहीं है, लेकिन उदाहरण के लिए लिनक्स और फ्रीबीएसडी मैन पेजों के साथ-साथ setvbufइसे "लाइन बफ़र" कहे जाने वाले POSIX विवरण । यहां तक ​​कि इसके लिए प्रतीकात्मक स्थिरांक भी है _IOLBF
इलकाचू

अच्छा अब आप बेहतर सीख गए हैं। यह बफरिंग रणनीति है GNU सी पुस्तकालय doco में वर्णित है, संक्षेप में यद्यपि। लॉरेंट बरकोट इस मामले पर अधिक स्पष्ट है। मैंने इसका भी उल्लेख किया है।
JdeBP

मुझे नहीं लगा कि "आपकी उम्मीद गलत है" आउटपुट बफ़रिंग के इस उत्कृष्ट विवरण के लिए एक अच्छा शीर्षक था। मुझे आशा है कि आपको कोई आपत्ति नहीं है कि मैंने इसे हटा दिया और उत्तर के प्रत्येक भाग के लिए कुछ वर्णनात्मक शीर्षकों को जोड़ा।
एंथनी जी -

2
@ilkkachu सी मानक वास्तव में "लाइन बफर" का उपयोग करता है। प्रति 7.21.3 फ़ाइलें , पैराग्राफ 3 : "जब एक धारा अप्रभावित होती है, ... जब एक स्ट्रीम पूरी तरह से बफ़र की जाती है, ... जब एक स्ट्रीम लाइन बफ़र की जाती है, तो वर्णों को एक होस्ट के रूप में या मेजबान वातावरण से प्रेषित किया जाना है। ब्लॉक करें जब एक नई-लाइन चरित्र का सामना किया जाता है ... "वास्तव में, सी मानक पांच बार" वाक्यांश "लाइन बफ़र" का सटीक वाक्यांश का उपयोग करता है। तो यह एक मिथ्या नाम नहीं है।
एंड्रयू हेनले

1
इसके अलावा, दृष्टिकोण को "स्मार्ट बफ़रिंग" के रूप में वर्णित किया गया है, जैसा कि मैं समझता हूं, ऐसा लगता है कि सी मानक "लाइन बफ़र" के रूप में वर्णित करता है। विशेष रूप से, newlines पर बफर को फ्लश करने के अलावा, "जब एक स्ट्रीम लाइन बफ़र की जाती है, तो वर्णों को होस्ट वातावरण से या जब ब्लॉक [...] इनपुट एक अप्रभावित स्ट्रीम पर या जब अनुरोध किया जाता है, तब प्रेषित किया जाता है। इनपुट को एक लाइन बफ़र स्ट्रीम पर अनुरोध किया गया है जिसमें होस्ट वातावरण से वर्णों के प्रसारण की आवश्यकता होती है। " तो यह एक ग्नू या बीएसडी क्वर्क नहीं है, बल्कि यह है कि भाषा क्या कहती है।
जॉन बोलिंगर

7

उपयोग

grep --line-buffered

बनाने के लिए एक समय में एक से अधिक लाइन बफर नहीं है।

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