एक फिल्टर के माध्यम से केवल STDERR पाइप


82

वहाँ किसी भी तरह से, एक फिल्टर के माध्यम से STDERR को STDOUT के साथ एकीकृत करने से पहले, बैश में है? यानी मुझे चाहिए

STDOUT ────────────────┐
                       ├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘

बजाय

STDOUT ────┐
           ├────[ filter ]───> terminal/file/whatever
STDERR ────┘

जवाबों:


64

यहां एक उदाहरण दिया गया है, जो विवरण के बाद फ़ाइल विवरणकों को bash में स्वैप करने के लिए बनाया गया है । A.out का आउटपुट 'STDXXX:' उपसर्ग के बिना निम्नलिखित है।

STDERR: stderr output
STDOUT: more regular

./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
more regular
stdErr output

उपरोक्त लिंक से उद्धरण:

  1. सबसे पहले stdout को & 3 में सहेजें (& 1 को 3 में विभाजित किया गया है)
  2. अगला stdout को stderr पर भेजें (& 2 को 1 में अनुक्रमित किया गया है)
  3. Stderr को & 3 (stdout) भेजें (और 3 को 2 में विभाजित किया गया है)
  4. नज़दीकी और 3 (और - 3 में धोखा दिया गया है)

1
यह मेरे लिए काम नहीं करता है। अंत में मैं इसके साथ काम करता हूं 3>&2 2>&1 1>&3-
ऐलेंग

3
सावधानी : यह मान लिया गया है कि एफडी 3 उपयोग में नहीं है, और फाइल डिस्क्रिप्टर 1 और 2 की अदला-बदली नहीं करता है, इसलिए आप इसे अभी तक किसी अन्य कमांड को पाइप करने के लिए नहीं जा सकते हैं। आगे और विस्तार के लिए इस उत्तर को देखें । {Ba, z} श के लिए बहुत अधिक क्लीनर सिंटैक्स के लिए, यह उत्तर देखें ।
टॉम हेल

25

टी एल; डॉ:

$ cmd 2> >(stderr-filter >&2)

उदाहरण:

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

यह बाश और zsh दोनों में काम करेगा। बैश इन दिनों बहुत अधिक सर्वव्यापी है, हालांकि, अगर आपको वास्तव में POSIX के लिए एक (वास्तव में शानदार) समाधान की आवश्यकता है sh, तो यहां देखें


व्याख्या

अब तक, ऐसा करने का सबसे आसान तरीका प्रक्रिया प्रतिस्थापन के माध्यम से STDERR को पुनर्निर्देशित करना है :

प्रक्रिया प्रतिस्थापन एक प्रक्रिया के इनपुट या आउटपुट को फ़ाइल नाम का उपयोग करने के लिए संदर्भित करने की अनुमति देता है। का रूप ले लेता है

>(list)

प्रक्रिया सूची को एसिंक्रोनस रूप से चलाया जाता है, और इसका इनपुट या आउटपुट फ़ाइल नाम के रूप में दिखाई देता है।

तो आपको प्रक्रिया के साथ जो कुछ मिलता है वह एक फ़ाइल नाम है।

जैसे आप कर सकते हैं:

$ cmd 2> filename

तुम कर सकते हो

$ cmd 2> >(filter >&2)

>&2रीडायरेक्ट के filterमूल STDERR को की STDOUT वापस।


1
इस उत्तर के साथ एक चेतावनी है: बैश प्रतिस्थापन प्रक्रिया के पूरा होने की प्रतीक्षा नहीं करता है , जबकि एफडी 1 और 2 को स्वैप करने की बाजीगरी करता है। यह महत्वपूर्ण हो सकता है। मैं exec 2> >(while .. read .. echo)एक स्क्रिप्ट में इस तरह से जला रहा था जो एक सिस्टम सेवा के रूप में चल रहा था। journald सेवा के fd2 को पकड़ता है, और '<N>' उपसर्ग से लॉग लेवल को संक्रमित करता है: <2> आउटपुट लाइनों के लिए तैयार हो जाता है, और आपको ERROR लेवल को जर्नल रिकॉर्ड्स को सौंपा जाता है। लेकिन कभी-कभी सिस्टमड मुख्य से बाहर निकलने पर पूरे प्रक्रिया समूह को मारने के लिए मज़बूत हो जाता है, इससे पहले कि वह अपना आखिरी लॉग कर सके, सबसे महत्वपूर्ण संदेश!
किमी किमी

अच्छा सरल उपाय है। कैविएट: क्रोन जॉब के हिस्से के रूप में इसका उपयोग करने में सावधानी बरतें; क्रोन द्वारा उपयोग किए जाने वाले कुछ गोले में प्रक्रिया प्रतिस्थापन उपलब्ध नहीं है।
क्विन कॉमेंडेंट

24

प्रक्रिया प्रतिस्थापन का एक भोली उपयोग stderrअलग से फ़िल्टरिंग की अनुमति देता है stdout:

:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err

ध्यान दें कि stderrपर बाहर आता है stderrऔर stdoutपर stdout, हम एक और subshell में पूरी बात लपेटकर और फ़ाइलों के लिए पुनः निर्देशित द्वारा देख सकते हैं जो oऔरe

( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e

क्यों :; शुरू में? मैं जादू लाइन के बिना की कोशिश की, और एक फर्क करने के लिए प्रतीत नहीं होता।
कोश्मार

1
कुछ लोग $कमांड प्रॉम्प्ट के रूप में उपयोग करते हैं । तब वे अक्सर शेल उदाहरण लिखते हैं जैसे $ cat /var/log/syslog | fgrep ...:। हालाँकि, यह लाइन कॉपी-पेस्ट करने योग्य नहीं है $:;एक संकेत की तरह लग रहा है, लेकिन मूल रूप से एक खोल सेशन नहीं है; तो आप पूरी लाइन को सुरक्षित रूप से चुन सकते हैं और चिपका सकते हैं।
सॉलिडस्नेक

23
ठीक है, लेकिन आप सिर्फ छोड़ सकते हैं:; और लाइन भी कॉपी-पेस्ट करने योग्य होगी :) मेरे लिए:; एक संकेत की तरह नहीं दिखता है, यह उदाहरण को स्पष्ट नहीं कर रहा था (कमांड को आउटपुट से अलग कर रहा है) लेकिन भ्रमित करना। हालाँकि मैं आपकी बात समझता हूँ और चलो वाक्यविन्यास / सम्मेलनों पर चर्चा नहीं करता।
कोश्मार

15

TL; DR: (बैश और zsh)

$ cmd 2> >(stderr-filter >&2)

उदाहरण:

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

StackExchange नेटवर्क पर कई उत्तरों के रूप हैं:

cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'

इसमें एक अंतर्निहित धारणा है: फ़ाइल डिस्क्रिप्टर 3 का उपयोग किसी और चीज़ के लिए नहीं किया जा रहा है।

इसके बजाय, नामित फ़ाइल डिस्क्रिप्टर का उपयोग करें, और {ba,z}shअगली उपलब्ध फ़ाइल डिस्क्रिप्टर> = 10 को आवंटित करेगा:

cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'

ध्यान दें कि फ़ाइल डिस्क्रिप्टर का नाम POSIX द्वारा समर्थित नहीं है sh

उपरोक्त के साथ अन्य मुद्दा यह है कि कमांड को फिर से एसटीडीयूएसटी और एसटीडीआरआर को फिर से स्वैप किए बिना कमांड को आगे नहीं बढ़ाया जा सकता है।

पोसिक्स में आगे की पाइपिंग की अनुमति देने के लिए sh, (और अभी भी एफडी 3 यह उपयोग नहीं है) यह जटिल हो जाता है :

(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1

इस प्रकार, इस धारणा और स्पष्ट रूप से वाक्यविन्यास को देखते हुए, आप ऊपर दिए गए TL; DR में सरल bash/ zshवाक्यविन्यास का उपयोग करके बेहतर होने की संभावना रखते हैं , और यहां समझाया गया है


8

मुझे बैश प्रक्रिया प्रतिस्थापन का उपयोग याद रखने में आसान है और इसका उपयोग करना आसान है क्योंकि यह मूल उद्देश्य को लगभग शब्दशः दर्शाता है। उदाहरण के लिए:

$ cat ./p
echo stdout
echo stderr >&2
$ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/'
sTdout
STderr

पहले sed कमांड को केवल stderr पर फ़िल्टर के रूप में और दूसरी sed कमांड को शामिल आउटपुट को संशोधित करने के लिए उपयोग करता है।

ध्यान दें कि 2> के बाद सफेद स्थान को सही ढंग से पार्स करने के लिए अनिवार्य है।


5

एडवांस बैश स्क्रिप्टिंग गाइड के इस पृष्ठ का अंतिम भाग "एक पाइप के लिए केवल स्ट्रीडर पुनर्निर्देशित करना" है।

# एक पाइप के लिए केवल stderr पुनर्निर्देशित।

exec 3>&1                              # Save current "value" of stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&-    # Close fd 3 for 'grep' (but not 'ls').
#              ^^^^   ^^^^
exec 3>&-                              # Now close it for the remainder of the script.

# धन्यवाद, एससी

यह वही हो सकता है जो आप चाहते हैं। यदि नहीं, तो ABSG का कुछ अन्य हिस्सा आपकी मदद करने में सक्षम होना चाहिए, यह उत्कृष्ट है।


हम संदर्भ के रूप में ABSG की सिफारिश करने में कुछ हिचकिचा रहे हैं, क्योंकि यह स्पष्ट रूप से मतभेदों को चिह्नित किए बिना प्रलेखन, पर्चे और राय को मिलाता है। कुछ खंडों में संदिग्ध सामग्री भी होती है, हालाँकि आप जिसे ठीक लगते हैं वह लिंक होता है।
त्रिकाल

3

नामित पाइपों पर एक नज़र डालें:

$ mkfifo err
$ cmd1 2>err |cat - err |cmd2

cat - errstdout और stderr के प्रतिच्छेद को नहीं तोड़ेंगे?
मार्टिन डेमेलो

@ मर्टिन - यह निर्भर करता है। यदि cmd1, cat, या cmd2 बफ़र्स आउटपुट, तो आप आउटपुट को अनुक्रम से बाहर देख सकते हैं।
भीड़
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.