पाइप, पाइप लाइन में डेटा प्रवाह कैसे होता है?


22

मुझे समझ नहीं आ रहा है कि कैसे पाइप लाइन में डेटा बहता है और उम्मीद है कि कोई स्पष्ट कर सकता है कि वहां क्या चल रहा है।

मुझे लगा कि कमांड की एक पाइपलाइन लाइन तरीके से फाइलों (पाठ, तार के सरणियों) को संसाधित करती है। (यदि प्रत्येक कमांड स्वयं लाइन द्वारा लाइन काम करती है।) टेक्स्ट की प्रत्येक लाइन पाइपलाइन से गुजरती है, तो कमांड पूरे इनपुट को पूरा करने के लिए पिछले की प्रतीक्षा नहीं करते हैं।

लेकिन ऐसा लगता है कि ऐसा नहीं है।

यहाँ एक उदाहरण है। पाठ की कुछ पंक्तियाँ हैं। मैं उन्हें अपरकेस करता हूं और प्रत्येक पंक्ति को दो बार दोहराता हूं। मैं ऐसा करता हूं cat text | tr '[:lower:]' '[:upper:]' | sed 'p'

प्रक्रिया का पालन करने के लिए हम इसे "अंतःक्रियात्मक रूप से" चला सकते हैं - इनपुट फ़ाइल नाम को छोड़ दें cat। पाइप लाइन का प्रत्येक भाग लाइन से चलता है:

$ cat | tr '[:lower:]' '[:upper:]'
alkjsd
ALKJSD
sdkj
SDKJ
$ cat | sed 'p'
line1
line1
line1
line 2
line 2
line 2

लेकिन पूरी पाइपलाइन मेरे साथ इनपुट खत्म होने का इंतजार करती है EOFऔर उसके बाद ही परिणाम प्रिंट करती है:

$ cat | tr '[:lower:]' '[:upper:]' | sed 'p'
I am writing...
keep writing...
now ctrl-D
I AM WRITING...
I AM WRITING...
KEEP WRITING...
KEEP WRITING...
NOW CTRL-D
NOW CTRL-D

क्या ऐसा होना चाहिए? यह लाइन-बाय-लाइन क्यों नहीं है?


यह पाइप नहीं है, यह catतब तक बफरिंग करता है जब तक स्टड बंद नहीं हो जाता।
गोल्डीलॉक्स

लेकिन trऔर sedcat
स्टैडेन

Stdio द्वारा उपयोग की जाने वाली चूक (जो मेरा मानना ​​है कि सभी उल्लिखित प्रोग्राम का उपयोग करते हैं) यह है कि stderr अप्रभावित है, और stdout लाइन बफ़र किया जाता है जब एक टर्मिनल पर लिखा जाता है और पूरी तरह से बफ़र किया जाता है अन्यथा (उदाहरण के लिए अगर यह किसी फ़ाइल या पाइप पर लिख रहा है) । कुछ कमांड्स में झंडे होते हैं जो स्टडआउट बफरिंग को बदल सकते हैं, लेकिन ऐसा लगता है कि tr नहीं है।
कैस्पर

जवाबों:


36

सी मानक I / O लाइब्रेरी ( stdio) के बाद एक सामान्य बफ़रिंग नियम है जो अधिकांश यूनिक्स प्रोग्राम का उपयोग करता है। यदि आउटपुट टर्मिनल पर जा रहा है, तो इसे प्रत्येक पंक्ति के अंत में फ्लश किया जाता है; अन्यथा यह तभी फ़्लश होता है जब बफर (मेरे लिनक्स / amd64 सिस्टम पर 8K, आप पर अलग हो सकता है) भरा हुआ है।

अपने सभी उपयोगिताओं सामान्य नियम निम्नलिखित थे, तो आप देखना होगा उत्पादन अपने उदाहरण के सभी में देरी ( cat|sed, cat|tr, और cat|tr|sed)। लेकिन इसका एक अपवाद है: GNU catकभी भी इसका आउटपुट बफ़र नहीं करता है। यह या तो उपयोग नहीं करता है stdioया यह डिफ़ॉल्ट stdioबफ़रिंग नीति को बदलता है ।

मुझे पूरा यकीन है कि आप GNU का उपयोग कर रहे हैं catऔर कुछ अन्य यूनिक्स का नहीं catक्योंकि अन्य इस तरह से व्यवहार नहीं करेंगे। पारंपरिक यूनिक्स के catपास -uविकल्पहीन आउटपुट का अनुरोध करने का विकल्प है। GNU विकल्प को catअनदेखा करता -uहै क्योंकि इसका आउटपुट हमेशा अप्रभावित रहता है।

तो जब भी आपके पास catबाईं तरफ एक पाइप होता है , तो जीएनयू सिस्टम में, पाइप के माध्यम से डेटा के पारित होने में देरी नहीं होगी। catयहां तक कि लाइन द्वारा लाइन में नहीं जा रहा है - अपने टर्मिनल कि कर रही है। जब आप बिल्ली के लिए इनपुट टाइप कर रहे होते हैं, तो आपका टर्मिनल "कैनोनिकल" मोड में होता है - लाइन-बेस्ड, जिसमें बैकस्पेस और ctrl-U जैसी एडिटिंग कीज़ होती हैं, जो आपको उस लाइन को एडिट करने का मौका देता है जिसे आपने भेजने से पहले टाइप किया है Enter

में cat|tr|sedउदाहरण के लिए, trअभी भी से डेटा प्राप्त कर रहा है catजैसे ही आप प्रेस Enter, लेकिन trपीछा कर रहा है stdioडिफ़ॉल्ट नीति: इसके उत्पादन एक पाइप लिए जा रहा है, तो यह प्रत्येक पंक्ति के बाद फ्लश नहीं करता है। यह दूसरा पाइप को लिखता है जब बफर भरा होता है, या जब एक ईओएफ प्राप्त होता है, जो भी पहले आता है।

sedstdioडिफ़ॉल्ट नीति का भी पालन कर रहा है, लेकिन इसका आउटपुट टर्मिनल पर जा रहा है, इसलिए जैसे ही यह समाप्त हो जाएगा, यह प्रत्येक पंक्ति को लिख देगा। यदि - यह आप पाइपलाइन के दूसरे छोर पर कुछ शो से पहले कितना लिखना चाहिए पर एक प्रभाव है sedथा ब्लॉक बफरिंग इसके उत्पादन, आप ज्यादा (भरने के रूप में दो बार टाइप करने के लिए होगा trके उत्पादन बफर और sed रों उत्पादन ' बफर)।

जीएनयू के sedपास -uविकल्प है यदि आप आदेश को उलटते हैं और उपयोग cat|sed -u|trकरते हैं तो आपको आउटपुट तुरंत फिर से दिखाई देगा। ( sed -uविकल्प कहीं और उपलब्ध हो सकता है लेकिन मुझे नहीं लगता कि यह एक प्राचीन यूनिक्स परंपरा है cat -u) जहां तक ​​मैं बता सकता हूं कि इसके लिए कोई समकक्ष विकल्प नहीं है tr

एक उपयोगिता है जिसे कहा जाता है stdbufजो आपको किसी भी कमांड के बफरिंग मोड को बदलने देता है जो stdioचूक का उपयोग करता है । यह थोड़ा नाजुक है क्योंकि इसका उपयोग LD_PRELOADसी लाइब्रेरी को समर्थन देने के लिए डिज़ाइन नहीं किया गया है, लेकिन इस मामले में यह काम करता है:

cat | stdbuf -o 0 tr '[:lower:]' '[:upper:]' | sed 'p'

1
धन्यवाद! बहुत बढ़िया जवाब। संभवतः मुझे किसी तरह से प्रश्न में बफरिंग का उल्लेख करना चाहिए, ताकि कोई इसे खोज सके।
xealits

teeऔर ddआमतौर पर अपने स्वयं के नियमों द्वारा भी खेलते हैं। जब कल्पनात्मक रूप से संयुक्त किया जाता है, तो तीन उपकरण stdbufपृष्ठभूमि वाली पाइपलाइनों में किसी भी आवश्यकता को बहुत कम कर सकते हैं ।
15

1
यह बिल्ली के बेकार उपयोग से बचने का एक कारण है ।
फोब्र्स

8

यह वास्तव में मुझे समझने के लिए कुछ सोचने और उत्तर देने के लिए और भी अधिक ले गया। महान प्रश्न (मैं इसे आगे बढ़ाऊंगा)।

आपने tr | sedऊपर अपने डिबगिंग आइटम में प्रयास करने की उपेक्षा की है :

>tr '[:lower:]' '[:upper:]' | sed 'p'
i am writing
still writing
now ctrl-d
I AM WRITING
I AM WRITING
STILL WRITING
STILL WRITING
NOW CTRL-D
NOW CTRL-D
>

तो जाहिर है trबफ़र्स। प्रति दिन कुछ नया सीखें!

संपादित करें :

जैसा कि मैं समझता हूं कि हमने इस कारण को अलग कर दिया है, लेकिन स्पष्टीकरण नहीं दिया है। यदि आप cat | tr, यह सही लिखता है, यदि आप cat | sed, यह तुरंत लिखता है, लेकिन यदि आप tr | sed, यह प्रतीक्षा करता है EOF। मेरा सुझाव है कि उत्तर को trया sedस्रोत कोड में दफन किया जा सकता है , और पाइप मुद्दा नहीं है।

संपादित करें :

मैं देख रहा हूं कि जब मैं अंतिम संपादन टाइप कर रहा था तो वम्पस ने स्पष्टीकरण प्रदान किया । धन्यवाद!


1
वास्तव में वे बफर! और लगभग 8kb लाइनों के साथ परीक्षण, जैसा कि Wumpus ने उल्लेख किया है, दिखाता है कि बफर वास्तव में 8Kb है। मैं कुछ प्रतिष्ठा को साझा करने के लिए दोनों उत्तरों को स्वीकार करना चाहता हूं, लेकिन मैं वम्पस को अधिक पूर्ण रूप में ले जाऊंगा। फिर भी धन्यवाद!
xealits

1
कोई बात नहीं, मेरा अनुभवजन्य उत्तर था, उनका जानकार था।
पोइसन एरोहेड

यह प्रश्न भी देखें जो दिखाता है कि कैसे उपयोग किया stdbufजा सकता है जो सहायक भी हो सकता है। unix.stackexchange.com/questions/182537/…
जो
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.