निष्पादन के उपयोग के बाद के सभी आदेशों के स्ट्राइडर को पुनर्निर्देशित करें


43

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

मैं 2>&1 | tee -a $DEBUGफ़ाइल में हर एक कमांड के लिए जोड़ना नहीं चाहता । मैं साथ रह सकता था | tee -a $DEBUG

मुझे याद है कि ऐसा कुछ करने का एक तरीका था exec 2>&1

वर्तमान में मैं निम्नलिखित की तरह कुछ का उपयोग कर रहा हूँ:

#!/bin/bash
DEBUGLOG=/tmp/debug
exec 2>&1
somecommand | tee -a $DEBUGLOG
somecommand2 | tee -a $DEBUGLOG
somecommand3 | tee -a $DEBUGLOG

लेकिन यह काम नहीं करता है। क्या किसी के पास कोई समाधान है / कारण बता सकता है?


1
कुछ गोले में, |&एक शॉर्टकट के रूप में काम करता है 2>&1 |, यह कम से कम थोड़ा अधिक सुविधाजनक है।
केविन

जवाबों:


39

एक बार में बहुत सारी कमांड पुनर्निर्देशित करने के समाधान के लिए:

#!/bin/bash
{
    somecommand 
    somecommand2
    somecommand3
} 2>&1 | tee -a $DEBUGLOG

आपका मूल समाधान काम क्यों नहीं करता है: 2> और 1 निष्पादित करें मानक त्रुटि आउटपुट को आपके शेल के मानक आउटपुट पर रीडायरेक्ट करेगा, यदि आप कंसोल से अपनी स्क्रिप्ट चलाते हैं, तो आपका कंसोल होगा। कमांड पर पाइप पुनर्निर्देशन केवल कमांड के standart आउटपुट को रीडायरेक्ट करेगा।

देखने के बिंदु पर somecommand, इसका मानक आउटपुट जुड़ा हुआ पाइप में चला जाता है teeऔर मानक त्रुटि शेल के मानक त्रुटि के रूप में उसी फ़ाइल / छद्म में चली जाती है, जिसे आप शेल के मानक आउटपुट पर रीडायरेक्ट करते हैं, जो कि होगा कंसोल यदि आप कंसोल से अपना प्रोग्राम चलाते हैं।

इसे समझाने का एक सही तरीका यह है कि वास्तव में क्या होता है:

यदि आप इसे टर्मिनल से चलाते हैं तो आपके शेल का मूल वातावरण इस तरह दिख सकता है:

stdin -> /dev/pts/42
stdout -> /dev/pts/42
stderr -> /dev/pts/42

मानक आउटपुट ( exec 2>&1) में मानक त्रुटि को पुनर्निर्देशित करने के बाद , आप ... मूल रूप से कुछ भी नहीं बदलते हैं। लेकिन अगर आप स्क्रिप्ट के standart आउटपुट को किसी फ़ाइल में रीडायरेक्ट करते हैं, तो आप इस तरह के माहौल को समाप्त कर देंगे:

stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /dev/pts/42

फिर शेल मानक त्रुटि को मानक आउटपुट में पुनर्निर्देशित करना इस तरह समाप्त होगा:

stdin -> /dev/pts/42
stdout -> /your/file
stderr -> /your/file

एक कमांड चलाना इस वातावरण को विरासत में देगा। यदि आप एक कमांड चलाते हैं और इसे टी करने के लिए पाइप करते हैं, तो कमांड का वातावरण होगा:

stdin -> /dev/pts/42
stdout -> pipe:[4242]
stderr -> /your/file

तो आपकी कमांड की मानक त्रुटि अभी भी वही है जो शेल अपने मानक त्रुटि के रूप में उपयोग करता है।

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


41

आप अपनी स्क्रिप्ट के शीर्ष पर इस तरह से निष्पादन का उपयोग कर सकते हैं:

exec > >(tee "$HOME/somefile.log") 2>&1

उदाहरण के लिए:

#!/bin/bash -

exec > >(tee "$HOME/somefile.log") 2>&1

echo "$HOME"
echo hi
date
date +%F
echo bye 1>&2

मुझे फ़ाइल $HOME/somefile.logऔर टर्मिनल को इस तरह आउटपुट देता है :

/home/saml
hi
Sun Jan 20 13:54:17 EST 2013
2013-01-20
bye

2
ध्यान दें कि यह बशीज़ का उपयोग करता है - यह अन्य गोले (जैसे, डैश) में काम नहीं कर सकता है। लेकिन सवाल के बाद से, निर्दिष्ट बैश, +1।
रिचर्ड हैनसेन

8
@ रीचर्डहेनसेन, प्रक्रिया प्रतिस्थापन एक ऐसी विशेषता है जिसे ksh द्वारा प्रस्तुत किया गया था, न कि bash द्वारा और यह भी zsh द्वारा समर्थित है इसलिए मैं इसे bashism नहीं कहूंगा
स्टीफन चेज़लस

6
@ स्टेफ़ेनचेज़लस: आप एक अच्छा बिंदु बनाते हैं। मैं सिर्फ यह बताना चाहता था कि वाक्य रचना POSIX मानक द्वारा समर्थित नहीं है और इस तरह से /bin/shलिपियों में सार्वभौमिक रूप से काम नहीं करेगा (कई लोग गलत तरीके से /bin/shस्क्रिप्ट में बैश सिंटैक्स का उपयोग करते हैं)।
रिचर्ड हैनसेन

मेरे लिए यह /dev/fd/62: Operation not supportedकोई सुराग देता है?
यूं

1
वहाँ लॉग फ़ाइल को छोड़कर stderr पुनर्निर्देशित नहीं करने का एक तरीका है? यदि मूल स्क्रिप्ट है myscriptऔर मैं चलाता ./myscript > /dev/nullहूं, तो मुझे अभी भी देखना चाहिए कि byeकौन से आता है echo bye >&2
मार्टिन जाम्बोन

0

किसी फ़ाइल पर stderr और stdout लिखें, स्क्रीन पर stderr प्रदर्शित करें (stdout पर)

exec 2> >(tee -a -i "$HOME/somefile.log")
exec >> "$HOME/somefile.log"

क्रोन के लिए उपयोगी है, इसलिए आप मेल द्वारा त्रुटियों (और केवल त्रुटियों) को प्राप्त कर सकते हैं

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