मानक त्रुटि स्ट्रीम (stderr) कैसे प्राप्त करें?


76

मैं एक ऑडियो क्लिप के मेटा जानकारी प्राप्त करने के लिए ffmpeg का उपयोग कर रहा हूं। लेकिन मैं इसे कुरेदने में असमर्थ हूं।

    $ ffmpeg -i 01-Daemon.mp3  |grep -i Duration
    FFmpeg version SVN-r15261, Copyright (c) 2000-2008 Fabrice Bellard, et al.
      configuration: --prefix=/usr --bindir=/usr/bin 
      --datadir=/usr/share/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib
      --mandir=/usr/share/man --arch=i386 --extra-cflags=-O2 
      ...

मैंने जाँच की, यह ffmpeg आउटपुट stderr को निर्देशित है।

$ ffmpeg -i 01-Daemon.mp3 2> /dev/null

इसलिए मुझे लगता है कि मिलान रेखाओं को पकड़ने के लिए grep एरर स्ट्रीम पढ़ने में असमर्थ है। हम त्रुटि स्ट्रीम को पढ़ने के लिए grep को कैसे सक्षम कर सकते हैं?

NixCraft लिंक का उपयोग करके , मैंने मानक त्रुटि स्ट्रीम को मानक आउटपुट स्ट्रीम पर पुनर्निर्देशित किया, फिर grep ने काम किया।

$ ffmpeg -i 01-Daemon.mp3 2>&1 | grep -i Duration
  Duration: 01:15:12.33, start: 0.000000, bitrate: 64 kb/s

लेकिन क्या होगा अगर हम stderout stderr को पुनर्निर्देशित नहीं करना चाहते हैं?


1
मेरा मानना ​​है कि grepकेवल stdout पर काम कर सकते हैं (हालांकि मैं उस स्रोत को वापस करने के लिए विहित स्रोत नहीं ढूँढ सकता), जिसका अर्थ है कि किसी भी स्ट्रीम को पहले stdout में बदलने की आवश्यकता है।
स्टीफन लासवर्स्की

9
@Tefan: grepकेवल स्टड पर काम कर सकता है। यह शेल द्वारा बनाया गया पाइप है जो grep के स्टड को दूसरे कमांड के स्टडआउट से जोड़ता है। और शेल केवल एक स्टडआउट को एक स्टड से जोड़ सकता है।
जिल्स

वूप्स, तुम सही हो। मुझे लगता है कि वास्तव में मेरे कहने का यही मतलब है, मैंने अभी इसके बारे में नहीं सोचा। धन्यवाद @ जील्स।
स्टीफन लासिवस्की

क्या आप चाहते हैं कि अभी भी इसका प्रिंटआउट निकाला जाए?
मिकेल

जवाबों:


52

यदि आप उपयोग bashक्यों नहीं कर रहे हैं तो अनाम पाइपों को नियोजित करें, जो कि फ्यूनहे ने कहा है:

ffmpeg -i 01-Daemon.mp3 2> >(grep -i Duration)


3
+1 नाइस! केवल बैश, लेकिन विकल्प की तुलना में क्लीनर।
मिकेल

1
+1 मैंने इसका उपयोग cpआउटपुट की जांच करने के लिए कियाcp -r dir* to 2> >(grep -v "svn")
बेटलिस्टा

5
आप फिर से stderr पर फ़िल्टर पुनः निर्देशित उत्पादन चाहते हैं, एक को जोड़ने >&2, जैसेcommand 2> >(grep something >&2)
Tlo

2
कृपया बताएं कि यह कैसे काम करता है। 2>फ़ाइल को पुनर्निर्देशित करता है, मुझे वह मिलता है। यह फ़ाइल से पढ़ता है >(grep -i Duration)। लेकिन फ़ाइल कभी संग्रहीत नहीं है? इस तकनीक को क्या कहा जाता है ताकि मैं इसके बारे में अधिक पढ़ सकूं?
मार्को एविलाज़े

1
यह एक पाइप बनाने के लिए "सिटैक्टिक शुगर" है (फाइल नहीं) और जब पूरा उस पाइप को हटा दें। वे प्रभावी रूप से अनाम हैं क्योंकि उन्हें फ़ाइल सिस्टम में नाम नहीं दिया गया है। बैश इस प्रक्रिया को प्रतिस्थापन कहते हैं।
जे क्यू

48

सामान्य गोले (यहां तक ​​कि zsh) में से कोई भी स्टडआउट से स्टडिन के अलावा अन्य पाइपों की अनुमति नहीं देता है। लेकिन सभी बॉर्न-शैली के गोले फ़ाइल डिस्क्रिप्टर रीसाइनमेंट (जैसा कि 1>&2) का समर्थन करते हैं । तो आप अस्थायी रूप से stdout को fd 3 और stderr को stdout में बदल सकते हैं, और बाद में fd 3 को stdout पर वापस रख सकते हैं। यदि stuffस्टडआउट पर कुछ आउटपुट और स्टडर पर कुछ आउटपुट का उत्पादन किया जाता है, और आप filterमानक आउटपुट को अछूता छोड़कर त्रुटि आउटपुट पर लागू करना चाहते हैं , तो आप उपयोग कर सकते हैं { stuff 2>&1 1>&3 | filter 1>&2; } 3>&1

$ stuff () {
  echo standard output
  echo more output
  echo standard error 1>&2
  echo more error 1>&2
}
$ filter () {
  grep a
}
$ { stuff 2>&1 1>&3 | filter 1>&2; } 3>&1
standard output
more output
standard error

यह दृष्टिकोण काम करता है। दुर्भाग्य से, मेरे मामले में, यदि एक गैर-शून्य रिटर्न मान वापस किया जाता है, तो यह खो जाता है - लौटाया गया मान मेरे लिए 0 है। यह हमेशा नहीं हो सकता है, लेकिन यह उस मामले में होता है जिसे मैं वर्तमान में देख रहा हूं। क्या इसे बचाने का कोई तरीका है?
फहीम मीठा

2
@FaheemMitha यकीन नहीं है कि आप क्या कर रहे हैं, लेकिन शायद pipestatusमदद मिलेगी
Gilles

1
@FaheemMitha, यहां भी set -o pipefailमददगार हो सकता है, जो इस बात पर निर्भर करता है कि आप त्रुटि स्थिति के साथ क्या करना चाहते हैं। (उदाहरण के लिए यदि आप set -eकिसी भी त्रुटि पर विफल हो गए हैं, तो आप set -o pipefailभी शायद चाहते हैं।)
वाइल्डकार्ड

@Wildcard हाँ, मैं set -eकिसी भी त्रुटि पर विफल रहा हूँ ।
फहीम मीठा

rcखोल पाइपिंग stderr अनुमति देता है। देखें मेरा उत्तर नीचे।
रॉल्फ

20

यह फुनेह की "टेम्प फाइल फाइल ट्रिक" के समान है, लेकिन इसके बजाय एक नामित पाइप का उपयोग करता है, जिससे आप आउटपुट होने पर उन्हें थोड़ा करीब से परिणाम प्राप्त कर सकते हैं, जो लंबे समय तक चलने वाले कमांड के लिए आसान हो सकता है:

$ mkfifo mypipe
$ command 2> mypipe | grep "pattern" mypipe

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

यदि आप बैश 4 का उपयोग कर रहे हैं, तो इसके लिए एक शॉर्टकट सिंटैक्स है command1 2>&1 | command2, जो है command1 |& command2। हालांकि, मेरा मानना ​​है कि यह विशुद्ध रूप से एक वाक्यविन्यास शॉर्टकट है, फिर भी आप STDERR को STDOUT में पुनर्निर्देशित कर रहे हैं।



1
यह |&सिंटैक्स फूला हुआ रूबी स्टैडर स्टैक निशान को साफ करने के लिए एकदम सही है। मैं अंत में बहुत परेशानी के बिना उन grep कर सकते हैं।
pgr

8

गिल्स और स्टीफन लासवर्स्की के उत्तर दोनों अच्छे हैं, लेकिन यह तरीका सरल है:

ffmpeg -i 01-Daemon.mp3 2>&1 >/dev/null | grep "pattern"

मैं मान रहा हूँ कि आप ffmpeg'sप्रिंटआउट नहीं चाहते हैं ।

यह काम किस प्रकार करता है:

  • पहले पाइप
    • ffmpeg और grep की शुरुआत होती है, ffmpeg के स्टडआउट को grep के स्टडिन में जाने से
  • अगले पुनर्निर्देशन, दाएं से बाएं
    • ffmpeg का stderr अपने स्टडआउट के लिए सेट है (वर्तमान में पाइप)
    • ffmpeg का स्टडआउट / dev / null पर सेट है

यह विवरण मुझे भ्रमित कर रहा है। आखिरी दो गोलियां मुझे लगता है कि "स्टडआउट के लिए पुनर्निर्देशित करें", फिर "रिडायरेक्टली स्टडआउट (अब, स्टडर के साथ) / देव / अशक्त"। हालाँकि, यह नहीं है कि यह वास्तव में क्या कर रहा है। उन बयानों पर पलटवार होता दिख रहा है।
स्टीव

1
दूसरी बुलेट में @Steve "stderr के साथ" नहीं है। क्या आपने unix.stackexchange.com/questions/37660/order-of-redirections देखा है ?
मिकेल

नहीं, मेरा मतलब है कि मेरी व्याख्या यह है कि आपने इसे अंग्रेजी में कैसे वर्णित किया। आपके द्वारा दिया गया लिंक बहुत उपयोगी है, हालाँकि।
स्टीव

इसे / dev / null में पुनर्निर्देशित करने की आवश्यकता क्यों थी?
कंवलजीत सिंह

7

इन परीक्षणों में प्रयुक्त स्क्रिप्ट के लिए नीचे देखें।

Grep केवल stdin पर काम कर सकता है, इसलिए आपको stderr स्ट्रीम को ऐसे रूप में परिवर्तित करना होगा जिसे Grep पार्स कर सके।

आम तौर पर, stdout और stderr दोनों आपकी स्क्रीन पर मुद्रित होते हैं:

$ ./stdout-stderr.sh
./stdout-stderr.sh: Printing to stdout
./stdout-stderr.sh: Printing to stderr

स्टडआउट को छिपाने के लिए, लेकिन फिर भी प्रिंट स्ट्रैंडर ऐसा करें:

$ ./stdout-stderr.sh >/dev/null
./stdout-stderr.sh: Printing to stderr

लेकिन grep stderr पर काम नहीं करेगा! आपको उम्मीद है कि निम्नलिखित कमांड उन लाइनों को दबाएगी जिनमें 'गलत' हैं, लेकिन ऐसा नहीं है।

$ ./stdout-stderr.sh >/dev/null |grep --invert-match err
./stdout-stderr.sh: Printing to stderr

यहाँ समाधान है।

निम्न बैश सिंटैक्स आउटपुट को stdout में छिपा देगा, लेकिन फिर भी stderr दिखाएगा। पहले हम stdout को / dev / null में पाइप करते हैं, फिर हम stderr को stdout में बदलते हैं, क्योंकि Unix पाइप केवल stdout पर काम करेंगे। आप अभी भी पाठ को टटोल सकते हैं।

$ ./stdout-stderr.sh 2>&1 >/dev/null | grep err
./stdout-stderr.sh: Printing to stderr

(ध्यान दें कि उपरोक्त आदेश है अलग तो ./command >/dev/null 2>&1है, जो एक बहुत ही आम आदेश है)।

यहाँ परीक्षण के लिए प्रयुक्त स्क्रिप्ट है। यह स्टडआउट के लिए एक लाइन और स्टडर के लिए एक लाइन प्रिंट करता है:

#!/bin/sh

# Print a message to stdout
echo "$0: Printing to stdout"
# Print a message to stderr
echo "$0: Printing to stderr" >&2

exit 0

यदि आप पुनर्निर्देश को चारों ओर घुमाते हैं, तो आपको सभी ब्रेसिज़ की आवश्यकता नहीं है। बस करो ./stdout-stderr.sh 2>&1 >/dev/null | grep err
मिकेल

3

जब आप एक कमांड के आउटपुट को दूसरे (उपयोग करते हुए |) पर पाइप करते हैं, तो आप केवल मानक आउटपुट को रीडायरेक्ट कर रहे हैं। तो यह बताना चाहिए कि क्यों

ffmpeg -i 01-Daemon.mp3 | grep -i Duration

आउटपुट नहीं है जो आप चाहते थे (यह काम करता है, हालांकि)।

यदि आप त्रुटि आउटपुट को मानक आउटपुट पर पुनर्निर्देशित नहीं करना चाहते हैं, तो आप किसी फ़ाइल में त्रुटि आउटपुट को रीडायरेक्ट कर सकते हैं, फिर बाद में इसे grep कर सकते हैं

ffmpeg -i 01-Daemon.mp3 2> /tmp/ffmpeg-error
grep -i Duration /tmp/ffmpeg-error

धन्यवाद। it does work, though, इसका मतलब है कि यह आपकी मशीन पर काम कर रहा है? दूसरे, जैसा कि आपने बताया कि हम पाइप का उपयोग करके केवल स्टडआउट को पुनर्निर्देशित कर सकते हैं। मुझे कुछ कमांड या बैश फीचर में दिलचस्पी है जो मुझे पुनर्निर्देशित करने की अनुमति देगा। (लेकिन अस्थायी फ़ाइल चाल नहीं)
एंड्रयू-डफ्रेसने

@ और मुझे मतलब है, कमांड काम करने के लिए जिस तरह से डिजाइन किया गया है वह काम करता है। यह सिर्फ उस तरीके से काम नहीं करता जैसा आप इसे करना चाहते हैं :)
phunehehe

मुझे ऐसे किसी भी तरीके का पता नहीं है जो किसी कमांड के एरर आउटपुट को दूसरे के स्टैंडर्ड इनपुट पर रिडायरेक्ट कर सके। दिलचस्प होगा अगर कोई इसे इंगित कर सकता है।
फुनेहे

2

आप धाराओं को स्वैप कर सकते हैं। grepमूल रूप से टर्मिनल में मानक आउटपुट पर जाने वाले आउटपुट प्राप्त करते समय यह आपको मूल मानक त्रुटि स्ट्रीम में सक्षम करेगा :

somecommand 3>&2 2>&1 1>&3- | grep 'pattern'

यह पहले आउटपुट के लिए एक नई फ़ाइल डिस्क्रिप्टर (3) खोलकर और मानक त्रुटि स्ट्रीम ( 3>&2) में सेट करके काम करता है । फिर हम मानक त्रुटि को मानक आउटपुट ( 2>&1) पर पुनर्निर्देशित करते हैं । अंत में मानक आउटपुट को मूल मानक त्रुटि पर पुनर्निर्देशित किया जाता है, और नई फ़ाइल डिस्क्रिप्टर को बंद कर दिया जाता है ( 1>&3-)।

आपके मामले में:

ffmpeg -i 01-Daemon.mp3 3>&2 2>&1 1>&3- | grep -i Duration

इसका परीक्षण:

$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep "error"
output
error

$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep -v "error"
output

1

मुझे rcइस मामले में शेल का उपयोग करना पसंद है ।

पहले पैकेज स्थापित करें (यह 1 एमबी से कम है)।

यह इस बात का एक उदाहरण है कि आप कैसे त्यागेंगे stdoutऔर पाइप stderrको कैसे बढ़ाएँगे rc:

find /proc/ >[1] /dev/null |[2] grep task

आप इसे बैश छोड़ने के बिना कर सकते हैं:

rc -c 'find /proc/ >[1] /dev/null |[2] grep task'

जैसा कि आपने देखा होगा कि वाक्यविन्यास सीधा है, जो इसे मेरा पसंदीदा समाधान बनाता है।

आप निर्दिष्ट कर सकते हैं कि आप किस फ़ाइल डिस्क्रिप्टर को पाइप वर्ण के ठीक बाद, कोष्ठक के अंदर पाइप करना चाहते हैं।

मानक फ़ाइल विवरणकों को इस प्रकार गिना जाता है:

  • 0: मानक इनपुट
  • 1: मानक ouptut
  • 2: मानक त्रुटि

0

बैश सबप्रोसेस उदाहरण पर एक भिन्नता:

दो पंक्तियाँ एक फ़ाइल के लिए stderr और टी stderr प्रतिध्वनि, टीआरई और पाइप वापस stdout करने के लिए बाहर

(>&2 echo -e 'asdf\nfff\n') 2> >(tee some.load.errors | grep 'fff' >&1)

stdout:

fff

some.load.errors (जैसे stderr):

asdf
fff

-1

इस आदेश का प्रयास करें

  • यादृच्छिक नाम के साथ फ़ाइल बनाएँ
  • फ़ाइल में आउटपुट भेजें
  • फ़ाइल की सामग्री को पाइप पर भेजें
  • ग्रेप

Ceva -> बस एक चर नाम (अंग्रेजी = कुछ)

ceva=$RANDOM$RANDOM$RANDOM; ffmpeg -i qwerty_112_0_0_record.flv 2>$ceva; cat $ceva | grep Duration; rm $ceva;

मैं उपयोग करूंगा /tmp/$ceva, वर्तमान निर्देशिका को अस्थायी फ़ाइलों के साथ जोड़ने से बेहतर - और आप मान रहे हैं कि वर्तमान निर्देशिका लेखन योग्य है।
रॉल्फ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.