bash - कैसे पाइप stderr करने के लिए, और stdout नहीं?




grep pipe (6)

मेरे पास एक ऐसा कार्यक्रम है जो stdout और stderr को जानकारी लिखता है, और मुझे stdout को अनदेखा करते समय, stderr पर आने वाले चीज़ों के माध्यम से grep करने की जरूरत है।

मैं निश्चित रूप से इसे 2 चरणों में कर सकता हूं:

command > /dev/null 2> temp.file
grep 'something' temp.file

लेकिन मैं temp फ़ाइलों के बिना ऐसा करने में सक्षम होना पसंद करेंगे। क्या कोई स्मार्ट पाइपिंग चाल है?


अगर आप सोचते हैं कि वास्तव में "रीडायरेक्ट" और "पाइप" के साथ क्या चल रहा है, तो चीजों को कल्पना करना बहुत आसान है। बैश में रीडायरेक्ट और पाइप एक चीज करते हैं: संशोधित करें जहां प्रक्रिया फ़ाइल वर्णनकर्ता 0, 1, और 2 बिंदु (देखें / proc / [pid] / fd / *)।

जब एक पाइप या "|" ऑपरेटर कमांड लाइन पर मौजूद है, पहली बात यह है कि बैश एक फीफो बनाता है और बाएं तरफ कमांड के एफडी 1 को इस फीफो में इंगित करता है, और दाएं तरफ कमांड के एफडी 0 को उसी फीफो में इंगित करता है।

इसके बाद, प्रत्येक पक्ष के लिए रीडायरेक्ट ऑपरेटर का मूल्यांकन बाएं से दाएं से किया जाता है , और जब भी वर्णनकर्ता का डुप्लिकेशन होता है तो वर्तमान सेटिंग्स का उपयोग किया जाता है। यह महत्वपूर्ण है क्योंकि चूंकि पाइप पहले स्थापित किया गया था, इसलिए एफडी 1 (बाएं तरफ) और एफडी 0 (दाएं तरफ) पहले से ही जो कुछ भी हो सकता है उससे बदल दिया गया है, और इनमें से कोई भी डुप्लिकेट उस तथ्य को प्रतिबिंबित करेगा।

इसलिए, जब आप निम्न की तरह कुछ टाइप करते हैं:

command 2>&1 >/dev/null | grep 'something'

यहां क्या होता है, क्रम में:

  1. एक पाइप (फीफो) बनाया गया है। "कमांड एफडी 1" इस पाइप की ओर इशारा किया गया है। "grep एफडी 0" भी इस पाइप की ओर इशारा किया गया है
  2. "कमांड एफडी 2" इंगित करता है कि "कमांड एफडी 1" वर्तमान में इंगित करता है (पाइप)
  3. "कमांड एफडी 1" को इंगित किया गया है / dev / null

तो, सभी आउटपुट जो "कमांड" अपने एफडी 2 (stderr) को लिखते हैं, वे पाइप के लिए अपना रास्ता बनाते हैं और दूसरी तरफ "grep" द्वारा पढ़ा जाता है। सभी आउटपुट जो "कमांड" अपने एफडी 1 (stdout) को लिखते हैं, वे / dev / null के लिए अपना रास्ता बनाते हैं।

यदि इसके बजाय, आप निम्न चलाते हैं:

command >/dev/null 2>&1 | grep 'something'

यहां क्या होता है:

  1. एक पाइप बनाया गया है और "कमांड एफडी 1" और "grep एफडी 0" इसकी ओर इशारा किया गया है
  2. "कमांड एफडी 1" को / dev / null पर इंगित किया गया है
  3. "कमांड एफडी 2" की ओर इशारा किया गया है जहां एफडी 1 वर्तमान में इंगित करता है (/ dev / null)

तो, "कमांड" से सभी stdout और stderr / dev / null पर जाएं। पाइप पर कुछ भी नहीं जाता है, और इस प्रकार "grep" स्क्रीन पर कुछ भी प्रदर्शित किए बिना बंद हो जाएगा।

यह भी ध्यान रखें कि रीडायरेक्ट (फ़ाइल डिस्क्रिप्टर) केवल-पढ़ने के लिए (<), केवल-लिखने (>), या पढ़ने-लिखने (<>) को पढ़ा जा सकता है।

एक अंतिम नोट चाहे कोई प्रोग्राम एफडी 1 या एफडी 2 को कुछ लिखता हो, पूरी तरह से प्रोग्रामर तक है। अच्छा प्रोग्रामिंग अभ्यास यह निर्देश देता है कि त्रुटि संदेशों को एफडी 2 और सामान्य आउटपुट एफडी 1 पर जाना चाहिए, लेकिन आपको अक्सर मैला प्रोग्रामिंग मिलती है जो दोनों को मिश्रित करती है या अन्यथा सम्मेलन को अनदेखा करती है।


इन उत्तरों में से सबसे अच्छा संयोजन, यदि आप करते हैं:

command 2> >(grep -v something 1>&2)

... तो सभी stdout stdout के रूप में संरक्षित है और सभी stderr stderr के रूप में संरक्षित है, लेकिन आप "कुछ" स्ट्रिंग के साथ stderr शुरुआत में किसी भी लाइन नहीं देख पाएंगे।

इसका स्टॉउट और स्टडरर को उलट या हटाने का अनूठा लाभ नहीं है, न ही उन्हें एक साथ जोड़ना, न ही किसी भी अस्थायी फ़ाइलों का उपयोग करना।



बैश में, आप प्रक्रिया प्रतिस्थापन का उपयोग करके एक सबहेल पर भी रीडायरेक्ट कर सकते हैं:

command > >(stdlog pipe)  2> >(stderr pipe)

हाथ में मामले के लिए:

command 2> >(grep 'something') >/dev/null

यह कमांड 1 stdout को कमांड 2 stdin पर रीडायरेक्ट करेगा, जबकि कमांड 1 stdout को छोड़कर।

exec 3>&1
command1 2>&1 >&3 3>&- | command2 3>&-
exec 3>&-

LDP से लिया गया


या उपयोग पर stderr और stdout से आउटपुट स्वैप करने के लिए: -

command 3>&1 1>&2 2>&3

यह एक नई फ़ाइल डिस्क्रिप्टर (3) बनाता है और इसे 1 (stdout) के समान स्थान पर असाइन करता है, फिर fd 2 (stdr) के समान स्थान पर fd 1 (stdout) असाइन करता है और अंत में fd 2 (stderr) को उसी पर असाइन करता है एफडी 3 (stdout) के रूप में रखें। Stderr अब stderr में संरक्षित stdout और पुराने stdout के रूप में उपलब्ध है। यह अधिक हो सकता है लेकिन उम्मीद है कि बैश फ़ाइल डिस्क्रिप्टर पर अधिक जानकारी देता है (प्रत्येक प्रक्रिया में 9 उपलब्ध हैं)।







stderr