पाइप से पढ़ते समय 'sed q' अलग तरह से क्यों काम करता है?


25

मैंने 'परीक्षण' नामक एक परीक्षण फ़ाइल बनाई जिसमें निम्नलिखित शामिल हैं:

xxx
yyy
zzz

मैंने कमांड चलाई:

(sed '/y/ q'; echo aaa; cat) < test

और मुझे मिल गया:

xxx
yyy
aaa
zzz

फिर मैं भागा:

cat test | (sed '/y/ q'; echo aaa; cat)

और पा लिया:

xxx
yyy
aaa

सवाल

sedपढ़ता है और प्रिंट करता है जब तक कि यह 'y' के साथ एक पंक्ति का सामना नहीं करता है, तब तक रुक जाता है। पहले मामले में, लेकिन दूसरी नहीं, बिल्ली बाकी को पढ़ती है और प्रिंट करती है।

क्या कोई बता सकता है कि व्यवहार में इस अंतर के पीछे क्या घटना है?

मैंने यह भी देखा कि यह इस तरह से Ubuntu 16.04 और Centos 6 में काम करता है, लेकिन Centos 7 में न तो 'zzz' का कमांड प्रिंट करता है।


मेरा अनुमान है कि cat(सब शेल में) पहले मामले में फ़ाइल डिस्क्रिप्टर का फिर से उपयोग कर सकता है, क्योंकि स्टड एक वास्तविक फ़ाइल से जुड़ा हुआ है। दूसरे मामले में, स्टडिन एक पाइप से है और एक वास्तविक फ़ाइल नहीं है। ध्यान दें कि (sed '/y/ q'; echo aaa; cat) < <(cat test)प्रिंट भी नहीं zzz
मार्टिन Nyolt 10

1
एक सरल उदाहरण: (head -n1; head -n1) < testऔरcat test | (head -n1; head -n1)
मार्टिन न्योल्ट

जवाबों:


22

जब इनपुट फ़ाइल तलाशने योग्य होती है (जैसे नियमित फ़ाइल से पढ़ना) या अन-सीकेबल (जैसे पाइप से पढ़ना), sed(और अन्य मानक उपयोगिताओं) अलग तरीके से व्यवहार करेंगे ( इस लिंकINPUT FILES में अनुभाग पढ़ें )।

डॉक्टर से उद्धरण:

जब एक मानक उपयोगिता एक शोध योग्य इनपुट फ़ाइल पढ़ती है और एक त्रुटि के बिना समाप्त हो जाती है, तो यह फ़ाइल के अंत तक पहुंचने से पहले, उपयोगिता सुनिश्चित करेगी कि खुले फ़ाइल विवरण में फ़ाइल ऑफ़सेट उपयोगिता द्वारा संसाधित अंतिम बाइट से ठीक पहले स्थित है।

तो में:

(sed '/y/ q'; echo aaa; cat) < test

sedqEOF तक पहुँचने से पहले uit कमांड का प्रदर्शन किया , इसलिए इसने zzzलाइन की शुरुआत में फाइल ऑफ़सेट को छोड़ दिया है, इसलिए बाक़ी catलाइनों को प्रिंट करना जारी रख सकते हैं (GNU सेड कुछ स्थिति में POSIX अनुरूप नहीं है, नीचे देखें)।

और डॉक्टर से जारी:

ऐसी फ़ाइलों के लिए जो खोज योग्य नहीं हैं, फ़ाइल की स्थिति उस फ़ाइल के लिए खुले फ़ाइल विवरण में ऑफसेट होती है जो अनिर्दिष्ट है

इस स्थिति में, व्यवहार अनिर्दिष्ट है। अधिकांश मानक उपकरण, शामिल sedइनपुट का यथासंभव उपभोग करेंगे। यह फ़ाइल ऑफ़सेट को पढ़ने के बिना yyyलाइन को पास करता है , और qयूट को पढ़ता है , इसलिए इसके लिए कुछ भी नहीं बचा है cat


GNU sedमानक के अनुरूप नहीं है, सिस्टम के stdio कार्यान्वयन और glibc संस्करण पर निर्भर करता है:

$ (gsed '/y/ q'; echo aaa; cat) < test
xxx
yyy
aaa

यहां, परिणाम मैक ओएसएक्स 10.11.6, वर्चुअल मशीन सेंटोस 7.2 - ग्लिबक 2.17, उबंटू 14.04 - ग्लिब 2. 2.19 से मिला, जो सीईपीएच बैकएंड के साथ ओपनस्टैक पर चलते हैं।

उन प्रणालियों पर, आप -uमानक व्यवहार को प्राप्त करने के लिए विकल्प का उपयोग कर सकते हैं :

(gsed -u '/y/ q'; echo aaa; cat) </tmp/test

और पाइप के लिए:

$ cat test | (gsed -u '/y/ q'; echo aaa; cat)
xxx
yyy
aaa
zzz

जो बहुत ही अक्षम प्रदर्शन करता है, क्योंकि sedएक बार में एक बाइट को पढ़ना पड़ता है। इससे आंशिक उत्पादन strace:

$ strace -fe read sh -c '{ sed -u "/y/q"; echo aaa; cat; } <test'
...
[pid  5248] read(3, "", 4096)           = 0
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "x", 1)             = 1
[pid  5248] read(0, "\n", 1)            = 1
xxx
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "y", 1)             = 1
[pid  5248] read(0, "\n", 1)            = 1
yyy
...

1
GNU के लिए sed, यह सिस्टम के stdio कार्यान्वयन पर निर्भर करता है। GNU सिस्टम (GNU libc के साथ) पर, GNU sedका अनुपालन किया exit()जाएगा क्योंकि stioio द्वारा प्रबंधित फ़ाइलों के लिए वापस लेसेक होगा।
स्टीफन चेज़लस

@ स्टीफनचेज़ेलस: इसे कैसे सत्यापित किया जाए? मेरे सेंटोस 7.2, उबंटू 14.04 वीएम के साथ, sedआज्ञाकारी नहीं है, मेरा मंज़र लैपटॉप करता है, सभी का समान sed संस्करण 4.2.2 है
cuonglm

@ स्टीफनचेज़ेलस: ऐसा लगता है जैसे हुड के नीचे कुछ हुआ। मेरी आभासी मशीनों पर, strace -f sh -c '{ sed "/y/q"; echo aaa; cat; } <test'दिखाओ कि कोई lseek()प्रदर्शन नहीं किया गया था, जबकि मेरे मेंजारो lseek()को पहले बुलाया गया था exit_group()
congongl

मुझे लगता है कि यह GNU libc के संस्करण के नीचे है। आप एक main() { char buf[999]; gets(buf); }'कार्यक्रम के साथ परीक्षण कर सकते हैं ।
स्टीफन चेज़लस

1
@ स्टीफनचेज़लस: पुष्टि। मेरे दोनों VMs में 2.17 और 2.19 हैं, जबकि मेरे manjaro में 2.23 है। क्या यह एक शानदार बग पर विचार करता है? क्या आपके पास glibc संस्करणों के बीच बदलाव के बारे में कोई जानकारी है
cuonglm
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.