स्क्रीन पर केवल stderr दिखाएं लेकिन फाइल करने के लिए stdout और stderr दोनों लिखें


24

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

स्पष्टता: मैं एक ही फाइल में stdout और stderr दोनों को समाप्त करना चाहता हूं। क्रम में वे होते हैं।
दुर्भाग्य से नीचे दिए गए उत्तरों में से कोई भी ऐसा नहीं करता है।


जवाबों:


14

यहां तक ​​कि किसी भी पुनर्निर्देशन के बिना, या कुछ भी नहीं के बावजूद >logfile 2>&1, आपको पीढ़ी के क्रम में आउटपुट देखने की गारंटी नहीं है।

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

"[टी] वह आदेश देता है कि वे वास्तव में केवल आवेदन के लिए जाने जाते हैं।" Stdout / Stderr में आउटपुट का आदेश एक प्रसिद्ध - क्लासिक, शायद - समस्या है।


7

जब आप निर्माण का उपयोग करते हैं: 1>stdout.log 2>&1दोनों stderr और stdout फ़ाइल पर पुनर्निर्देशित हो जाते हैं क्योंकि stdout पुनर्निर्देशन को stderr पुनर्निर्देशन से पहले सेट किया जाता है।

आप की विपरीत आप प्राप्त कर सकते हैं, तो stdout एक फाइल करने के लिए निर्देशित कर दिये और फिर कॉपी stderr करने के लिए stdout ताकि आप पाइप इसे करने के लिए कर सकते हैं tee

$ cat test
#!/bin/sh
echo OUT! >&1
echo ERR! >&2

$ ./test 2>&1 1>stdout.log | tee stderr.log
ERR!

$ cat stdout.log
OUT!

$ cat stderr.log
ERR!

यह आपको एक ही फाइल में दो स्ट्रीम लॉग करने नहीं देता है।
आर्टिस्टोक्स

1
@ कार्टिस्टेक्स: आप बस tee -aएक ही फाइल के साथ 1>दोनों आउटपुट को एक ही फाइल में समिट करने के लिए इस्तेमाल कर सकते हैं । कुछ इस तरह:./test 2>&1 1>out+err.log | tee -a out+err.log
mmoya

मुझे पता नहीं क्यों, लेकिन यह wget -O - www.google.deमेरे लिए काम नहीं करता है। (नीचे दिए गए समाधान के साथ तुलना करें)
कलाकारोए

4
उपयोग tee -aकरने से मज़बूती से उसी आउटपुट का उत्पादन नहीं होगा जो कंसोल पर होगा यदि कुछ भी पुनर्निर्देशित नहीं किया गया था। जो आउटपुट से होकर गुजरता teeहै वह कमांड से सीधे आने वाले आउटपुट की तुलना में थोड़ा विलंबित हो सकता है, और इसलिए बाद में लॉग में दिखाई दे सकता है।
गिल्स एसओ- बुराई को रोकना '

यह मेरे लिए काम नहीं करता है, आउट + इरलॉग खाली है। और हां, मैं एक ही फाइल में स्टाडरर और स्टैंडर्ड आउट चाहता हूं
एंड्रियास

7

मैं निम्नलिखित लाइन को बैश स्क्रिप्ट के शीर्ष पर रखकर इसे पूरा करने में सक्षम रहा:

exec 1>>log 2> >(tee -a log >&2)

यह फ़ाइल log( 1>>log) को stdout रीडायरेक्ट करेगा , फिर फ़ाइल को stderr log( 2> >(tee -a log) और इसे वापस stderr पर निर्देशित करें ( >&2)इस तरह, मुझे एक एकल फ़ाइल मिलती है log, जो क्रम में stdout और stderr दोनों को दिखाती है, और stderr भी है। हमेशा की तरह स्क्रीन पर प्रदर्शित।

पकड़ यह है कि यह केवल तभी काम करता है जब मैं फ़ाइल में संलग्न होता हूं। यदि मैं संलग्न नहीं करता हूं, तो ऐसा प्रतीत होता है कि दो पुनर्निर्देशन एक-दूसरे को पसंद करते हैं, और मुझे केवल एक आउटपुट प्राप्त होता है।


कस्टम स्ट्रिंग को शामिल करने के लिए STDERR लाइनों को "संशोधित" करने के लिए इसे प्राप्त करने का कोई भी तरीका ताकि आप उस पर आसानी से पकड़ कर सकें?
IMTheNachoMan

1

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

{ { echo out; echo err 1>&2; } 2>&1 >&3 | tee /dev/tty; } >log 3>&1
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^   ^^^^^^^^^^^^    ^^^^^^^^^
  command produces output      stdout3                    log
  command produces error       stderr1   dup to terminal  log

यह भी, मेरे लिए काफी काम नहीं करता है, मुझे पहले stdout लाइनें मिलती हैं, और फिर 'log' फ़ाइल में सभी stderr लाइनें। उदाहरण: {{इको आउट; इको इर्रिट 1> & 2; इको आउट 2; इको इरेट 2 1> & 2; } 2> और 1> & 3 | टी / देव / ट्टी; }> लॉग 3> और 1
एंड्रियास

1
@ संकेत: ओह, डुह, teeयहां भी देरी का परिचय देता है। मुझे नहीं लगता कि शुद्ध शेल समाधान है। वास्तव में मुझे आश्चर्य है कि क्या किसी तरह से आवेदन को संशोधित किए बिना कोई समाधान है।
गिल्स एसओ- बुराई को रोकना '

1

स्क्रीन पर Stderr लिखने के लिए और BOTH stderr और stdout को एक फ़ाइल में लिखने के लिए - और उसके पास stderr और stdout के लिए लाइनें हैं, उसी क्रम में वे दोनों स्क्रीन पर लिखे गए थे:

एक मुश्किल समस्या बन जाती है, विशेष रूप से "एक ही अनुक्रम" होने के बारे में हिस्सा अगर आप बस उन्हें स्क्रीन पर लिखेंगे, तो आप उम्मीद करेंगे। सरल शब्दों में: प्रत्येक को अपनी फ़ाइल में लिखें, प्रत्येक पृष्ठभूमि (प्रत्येक फ़ाइल में) को चिह्नित करने के लिए कुछ पृष्ठभूमि-प्रक्रिया जादू करें जो सटीक समय पर लाइन का उत्पादन किया गया था, और फिर: स्क्रीन पर stderr फ़ाइल को "पूंछ - फाइल" करें , लेकिन BOTH "stderr" और "stdout" को एक साथ देखने के लिए - अनुक्रम में - दो फ़ाइलों को क्रमबद्ध करें (प्रत्येक पंक्ति पर सटीक-समय के निशान के साथ)।

कोड:

# Set the location of output and the "first name" of the log file(s)
pth=$HOME
ffn=my_log_filename_with_no_extension
date >>$pth/$ffn.out
date >>$pth/$ffn.err
# Start background processes to handle 2 files, by rewriting each one line-by-line as each line is added, putting a label at front of line
tail -f $pth/$ffn.out | perl -nle 'use Time::HiRes qw(time);print substr(time."0000",0,16)."|1|".$_' >>$pth/$ffn.out.txt &
tail -f $pth/$ffn.err | perl -nle 'use Time::HiRes qw(time);print substr(time."0000",0,16)."|2|".$_' >>$pth/$ffn.err.txt &
sleep 1
# Remember the process id of each of 2 background processes
export idout=`ps -ef | grep "tail -f $pth/$ffn.out" | grep -v 'grep' | perl -pe 's/\s+/\t/g' | cut -f2`
export iderr=`ps -ef | grep "tail -f $pth/$ffn.err" | grep -v 'grep' | perl -pe 's/\s+/\t/g' | cut -f2`
# Run the command, sending stdout to one file, and stderr to a 2nd file
bash mycommand.sh 1>>$pth/$ffn.out 2>>$pth/$ffn.err
# Remember the exit code of the command
myexit=$?
# Kill the two background processes
ps -ef | perl -lne 'print if m/^\S+\s+$ENV{"idout"}/'
echo kill $idout
kill $idout
ps -ef | perl -lne 'print if m/^\S+\s+$ENV{"iderr"}/'
echo kill $iderr
kill $iderr
date
echo "Exit code: $myexit for '$listname', list item# '$ix', bookcode '$bookcode'"

हां, यह विस्तृत लगता है, और इसका परिणाम 4 आउटपुट फाइलों में से है (जिनमें से 2 आप हटा सकते हैं)। ऐसा लगता है कि यह हल करने के लिए एक कठिन समस्या है, इसलिए इसने कई तंत्रों को लिया।

अंत में, बीओटीएच स्टडआउट और स्टेडर से परिणाम देखने के लिए जिस क्रम की आप अपेक्षा करेंगे, वह इस प्रकार है:

cat $pth/$ffn.out.txt $pth/$ffn.err.txt | sort

केवल यही कारण है कि अनुक्रम कम से कम बहुत करीब है जो कि यह दोनों stdout होता है और Stderr बस स्क्रीन पर चला गया है: हर एक पंक्ति को टाइमस्टैम्प के साथ मिलीसेकंड तक चिह्नित किया जाता है।

इस प्रक्रिया के साथ स्क्रीन पर स्टडर देखने के लिए, इसका उपयोग करें:

tail -f $pth/$ffn.out

आशा है कि किसी को बाहर लाने में मदद करता है, जो मूल प्रश्न पूछे जाने के लंबे समय बाद यहां पहुंचे।


+1 सरासर प्रयास के लिए, मेरे पास एक समान विचार था (पर्ल के माध्यम से दोनों धाराएं) लेकिन इसे लागू करने के लिए संघर्ष कर रहा था। मैं जांच करूंगा कि क्या यह मेरे लिए काम करता है (यानी, अगर यह वास्तव में आउटपुट के क्रम को बनाए रखता है, क्योंकि अन्य समाधान यहां स्टडर और स्टडआउट के टैगिंग के बीच एसिंक्रोनसिटी के कारण चीजों को थोड़ा शिफ्ट करते हैं)
ओलिवियर ड्यूलैक

0

आज्ञा दें fकि आप चाहते हैं कि निष्पादित हो, तो यह

( exec 3>/tmp/log; f 2>&1 1>&3 |tee >(cat)>&3 )

आपको वह देना चाहिए जो आप चाहते हैं। उदाहरण के लिए wget -O - www.google.deइस तरह दिखेगा:

( exec 3>/tmp/googlelog; wget -O - www.google.de 2>&1 1>&3 |tee >(cat)>&3 )

1
यह लगभग मेरे लिए काम करता है, लेकिन लॉग फ़ाइल में मुझे पहले सभी stdout लाइनें मिलती हैं, और फिर सभी stderror lines। मैं चाहता हूं कि जैसे वे होते हैं वैसे ही उन्हें प्राकृतिक क्रम में रखा जाए।
एंड्रियास

0

यह देखते हुए कि मैंने यहां क्या पढ़ा है, इसका एकमात्र समाधान मैं देख सकता हूं कि प्रत्येक पंक्ति चाहे वह STOUT हो या STERR एक टाइमलाइन / टाइमस्टैम्प के साथ हो। दिनांक +% s सेकंड में मिल जाएगा, लेकिन यह क्रम बनाए रखने के लिए धीमा होगा। इसके अलावा लॉग को किसी तरह सुलझाना होगा। जितना मैं सक्षम हूं उससे अधिक काम।


0

मैं इस सटीक आवश्यकता के साथ संघर्ष किया है, और अंत में एक सरल समाधान नहीं मिल सका। इसके बजाय मैंने क्या किया:

TMPFILE=/tmp/$$.log
myCommand > $TMPFILE 2>&1
[ $? != 0 ] && cat $TMPFILE
date >> myCommand.log
cat $TMPFILE >> myCommand.log
rm -f $TMPFILE

यह लॉग फ़ाइल में, उचित इंटरलेयर्ड क्रम में स्टैडआउट और स्टॉडर को जोड़ता है। और यदि कोई त्रुटि हुई (जैसा कि कमांड की निकास स्थिति द्वारा निर्धारित किया गया है), यह पूरे आउटपुट (stdout और stderr) को stdout में भेज देता है , फिर से उचित रूप से क्रमबद्ध क्रम में। मैंने इसे अपनी आवश्यकताओं के लिए एक उचित समझौता माना। यदि आप बढ़ते मल्टी-रन के बजाय सिंगल-रन लॉग फ़ाइल चाहते हैं, तो यह और भी सरल है:

myCommand > myCommand.log 2>&1
[ $? != 0 ] && cat myCommand.log

0

कमांडर-प्रतिस्थापित करने के लिए stderr tee -a, और एक ही फाइल के लिए संलग्न stdout:

./script.sh 2> >(tee -a outputfile) >>outputfile

और ध्यान दें: सही क्रम भी सुनिश्चित करें (लेकिन बिना स्टॉडर-शो के) 'उम्मीद' टूल से 'अनबॉर्फ़र' कमांड है, जो tty का अनुकरण करता है और stdout / इरेज़ को क्रम में रखता है क्योंकि यह टर्मिनल पर दिखाएगा:

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