पाइप, {सूची; } केवल कुछ कार्यक्रमों के साथ काम करता है


13

इस तरह के अप्रत्याशित व्यवहार के लिए बिजली उपयोगकर्ताओं से स्पष्टीकरण की आवश्यकता है:

ps -eF | { head -n 1;grep worker; }
UID        PID  PPID  C    SZ   RSS PSR STIME TTY          TIME CMD
root       441     2  0     0     0   2 paź15 ?       00:00:00 [kworker/2:1H]

जबकि सब कुछ ठीक लग रहा है

ls -la / | { head -n 1;grep sbin; }

से केवल आउटपुट प्रदर्शित करता है head

... मैंने सोचा था stdout 2>&1और मेरे लिए न तो यह काम अजीब है, न ही कोई स्पष्टीकरण या सुझाव है कि इसे कैसे संभालना है?


1
आखिरी को सब कुछ पता लगाना चाहिए। headऔर grepवहाँ कुछ भी नहीं है।
जोर्डनम

हाँ आप सही है। लेकिन इसके बजाय, ps -eF ls -la / not के समय काम क्यों करता है?
ast

जवाबों:


9

मैंने कुछ जांच का उपयोग किया straceऔर यह प्रतीत होता है कि जिस तरह से पाइप लाइन के बाईं ओर कार्यक्रम यह टर्मिनल को लिख रहा है। जब lsकमांड निष्पादित किया जाता है तो यह एक ही बार में सभी डेटा लिखता है write()। इसके कारण headसभी स्टड की खपत होती है।

दूसरी ओर ps, बैचों में डेटा लिखते हैं, इसलिए केवल पहले write()का उपभोग किया जाता है head, और फिर यह मौजूद होता है। बाद में कॉल write()नवविवाहित grepप्रक्रिया में जाएगी।

इसका मतलब यह है कि यदि आप जिस प्रक्रिया के लिए प्रयास कर रहे हैं grepवह पहले नहीं होती थी , तो यह काम नहीं करेगा write(), क्योंकि grepयह सभी डेटा को देखने के लिए नहीं मिलता है (यह केवल डेटा को पहली पंक्ति से भी कम देखता है)।

यहाँ मेरे सिस्टम पर pid 1 के लिए क्रेप करने की कोशिश करने का एक उदाहरण है:

$ ps -eF | { head -n2; }
UID        PID  PPID  C    SZ   RSS PSR STIME TTY          TIME CMD
root         1     0  0  1697  3768   2 Oct03 ?        00:00:03 /lib/systemd/systemd
$ ps -eF | grep '/lib/systemd/systemd$'
root         1     0  0  1697  3768   2 Oct03 ?        00:00:03 /lib/systemd/systemd
$ ps -eF | { head -n1; grep '/lib/systemd/systemd$'; }
UID        PID  PPID  C    SZ   RSS PSR STIME TTY          TIME CMD

आपका ps -eFउदाहरण केवल संयोग से काम करता है।


महान और व्यापक expalnation बहुत बहुत शुक्रिया
ast

1
वास्तव में यह एक दौड़ की स्थिति से अधिक है। यह सिर्फ इतना है कि यह धीमी गति से कई write()कॉल कर रहा है। यदि headयह read()कॉल करने के लिए धीमा था (जैसे कि पाइप बफ़र में सभी डेटा था), यह दोनों में समान व्यवहार प्रदर्शित करेगा lsऔर ps
पैट्रिक

6

यह glibc में बफरिंग के कारण होता है। lsआउटपुट के मामले में एक आंतरिक बफर में है और इस तरह के रूप में पारित कर दिया है headps -eFआउटपुट के लिए , आउटपुट बड़ा है और इसलिए एक बार headखत्म grepहो जाने के बाद, निम्नलिखित को (लेकिन पूरे नहीं) आउटपुट के शेष भाग मिलते हैं ps

आप पाइप को अन-बफरिंग करके इससे छुटकारा पा सकते हैं - उदाहरण के लिए sed -u(मुझे यकीन नहीं है कि यह GNU एक्सटेंशन नहीं है):

$ ls -al / | sed -u "#" | { head -n 1; grep bin; }
total 76
drwxr-xr-x   2 root root  4096 Oct  2 21:52 bin
drwxr-xr-x   2 root root  8192 Oct  3 01:54 sbin

4

क्या हो रहा है कि head -n 11 से अधिक पंक्ति पढ़ता है। इष्टतम थ्रूपुट के लिए, सिर बाइट्स के टुकड़े पढ़ता है, इसलिए यह एक बार में 1024 बाइट्स पढ़ सकता है, और फिर पहली पंक्ति ब्रेक के लिए उन बाइट्स के माध्यम से देख सकता है। चूंकि 1024 बाइट्स के बीच में लाइन ब्रेक हो सकता है, इसलिए बाकी डेटा खो जाता है। इसे पाइप पर वापस नहीं रखा जा सकता है। तो अगली प्रक्रिया जो निष्पादित होती है वह केवल बाइट्स 1025 और पर मिलती है।

आपका पहला कमांड सफल होता है क्योंकि kworkerप्रक्रिया उसके बाद होती है जो पहले headपढ़ी जाती है।

इसके लिए काम करने के लिए, headएक बार में 1 वर्ण पढ़ना होगा। लेकिन यह बेहद धीमा है, इसलिए यह नहीं है।
इस तरह से कुशलतापूर्वक कुछ करने का एकमात्र तरीका यह है कि एक ही प्रक्रिया "सिर" और "grep" दोनों करें।

यहाँ यह करने के 2 तरीके हैं:

echo -e '1\n2\n3\n4\n5' | perl -ne 'print if $i++ == 0 || /4/'

या

echo -e '1\n2\n3\n4\n5' | awk '{if (NR == 1 || /4/) print }'

और भी बहुत कुछ हैं ...


हाँ मैंने इस कार्य को संभालने के लिए 'जागने का तरीका' जाना है, लेकिन सोच रहा था कि {सूची के साथ व्यवहार इतना अप्रत्याशित क्यों था; }। यह कैसे काम करता है स्पष्ट करने के लिए धन्यवाद। मैं उपरोक्त सभी उत्तरों से प्रभावित हूँ
ast

2

यदि आप केवल पहली पंक्ति या दो चाहते हैं, तो निम्न प्रकार की ट्रिक काम करती है और आउटपुट स्ट्रीम को पढ़ने के लिए दो अलग-अलग कमांड्स का उपयोग करके होने वाली बफरिंग समस्याओं से बचा जाता है:

$ ps -eF   | { IFS= read -r x ; echo "$x" ; grep worker; }
$ ls -la / | { IFS= read -r x ; echo "$x" ; grep sbin; }

readअंतर्निहित है खोल करने के लिए और सिर्फ उत्पादन एक लाइन के लिए इनपुट की एक पूरी बफर का उपभोग नहीं करता, इसलिए का उपयोग कर readपत्ते निम्न आदेश के लिए उत्पादन के सभी बाकी।

यदि आप अपने उदाहरणों द्वारा दर्शाई गई बफ़रिंग समस्याओं को दूर करना चाहते हैं, जो दो अलग-अलग कमांडों का उपयोग करते हैं, sleepतो टाइमिंग के मुद्दों को खत्म करने के लिए उनमें से एक को जोड़ें और दाईं ओर दिए गए आदेशों को पढ़ने से पहले अपने सभी आउटपुट को उत्पन्न करने के लिए बाईं ओर कमांड को अनुमति दें। यह:

$ ps -eF   | { sleep 5 ; head -n 1 ; grep worker; }
$ ls -la / | { sleep 5 ; head -n 1 ; grep sbin; }

अब, उपरोक्त दोनों उदाहरण एक ही तरह से विफल हो जाते हैं - headआउटपुट का एक पूरा बफर पढ़ता है बस एक लाइन का उत्पादन करने के लिए, और वह बफर निम्नलिखित के लिए उपलब्ध नहीं है grep

आप कुछ उदाहरणों का उपयोग करके बफ़रिंग समस्या को और भी स्पष्ट रूप से देख सकते हैं जो आउटपुट लाइनों की संख्या बताती है ताकि आप बता सकें कि कौन सी लाइनें गायब हैं:

$ ps -eF          | cat -n | { sleep 5 ; head -n 1 ; head ; }
$ ls -la /usr/bin | cat -n | { sleep 5 ; head -n 1 ; head ; }

बफ़रिंग समस्या को देखने का एक सरल तरीका यह है seqकि संख्याओं की सूची तैयार की जाए। हम आसानी से बता सकते हैं कि कौन सी संख्या गायब है:

$ seq 1 100000    | { sleep 5 ; head -n 1 ; head ; }
1

1861
1862
1863
1864
1865
1866
1867
1868
1869

नींद में देरी के साथ भी पहली पंक्ति के काम को पढ़ने और गूँजने के लिए शेल का उपयोग करके मेरा ट्रिक सॉल्यूशन जोड़ा गया है:

$ seq 1 100000 | { sleep 5 ; IFS= read -r x ; echo "$x" ; head ; }
1
2
3
4
5
6
7
8
9
10
11

नीचे headबफ़रिंग मुद्दों को दिखाते हुए एक पूर्ण उदाहरण दिया गया है, जिसमें दिखाया गया है कि headहर बार अपनी पांच लाइनों का उत्पादन करने के लिए आउटपुट का एक पूरा बफर कैसे खपत करता है। वह भस्म बफर headअनुक्रम में अगले कमांड के लिए उपलब्ध नहीं है :

$ seq 1 100000 | { sleep 5 ; head -5 ; head -5 ; head -5 ; head -5 ; }
1
2
3
4
5

1861
1862
1863
1864
499
3500
3501
3502
3503
7
5138
5139
5140
5141

संख्या को देखते हुए 1861ऊपर, हम गणना कर सकते हैं बफर के आकार के आधार पर इस्तेमाल किया जा रहा headकी गणना के द्वारा seqसे उत्पादन 1करने के लिए 1860:

$ seq 1 1860 | wc -c
8193

हम देखते हैं कि headएक समय में पाइप उत्पादन का पूरा 8KB (8 * 1024 बाइट्स) पढ़ने से बफरिंग होती है, यहां तक ​​कि अपने स्वयं के आउटपुट की कुछ लाइनों का उत्पादन करने के लिए भी।

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