2008-11-24 24 views
119

क्या बोर्न शेल स्क्रिप्ट के सभी आउटपुट को कहीं भी रीडायरेक्ट करना संभव है, लेकिन स्क्रिप्ट के अंदर शैल कमांड के साथ ही?मैं स्क्रिप्ट के भीतर पूरी शेल स्क्रिप्ट के आउटपुट को रीडायरेक्ट कैसे करूं?

एक एकल आदेश के उत्पादन में रीडायरेक्ट कर रहा है आसान है, लेकिन मैं और अधिक कुछ इस तरह हैं:

#!/bin/sh 
if [ ! -t 0 ]; then 
    # redirect all of my output to a file here 
fi 

# rest of script... 

अर्थ: यदि स्क्रिप्ट (उदाहरण के लिए, क्रॉन के लिए) चलाया जाता है गैर सहभागी, उत्पादन बंद को बचाने एक फाइल के लिए सब कुछ। यदि एक खोल से अंतःक्रियात्मक रूप से चलाया जाता है, तो उत्पादन सामान्य रूप से stdout पर जाने दें।

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

अद्यतन: यहोशू के जवाब स्पॉट पर है, लेकिन मैं यह भी बचाने के लिए और पूरी स्क्रिप्ट है, जो इस तरह से किया जाता है चारों ओर stdout और stderr बहाल करने के लिए चाहता था:

# save stdout and stderr to file descriptors 3 and 4, then redirect them to "foo" 
exec 3>&1 4>&2 >foo 2>&1 

# ... 

# restore stdout and stderr 
exec 1>&3 2>&4 
+2

$ अवधि के लिए परीक्षण का सबसे अच्छा तरीका इंटरैक्टिव मोड के लिए परीक्षण करने के लिए नहीं है। इसके बजाय, जांच करें कि क्या स्टडीन एक टीटीआई (test -t 0) है। –

+2

दूसरे शब्दों में: यदि [! -टी 0]; फिर exec> somefile 2> & 1; फाई –

+0

सभी अच्छाई के लिए यहाँ देखें: [http://tldp.org/LDP/abs/html/io-redirection.html](http://tldp.org/LDP/abs/html/io-redirection.html) मूल रूप से यहोशू ने क्या कहा था। exec> फ़ाइल किसी विशिष्ट फ़ाइल पर stdout को रीडायरेक्ट करता है, exec <फ़ाइल फ़ाइल द्वारा stdin को प्रतिस्थापित करता है, आदि। यह सामान्य के समान है लेकिन exec का उपयोग करना (अधिक जानकारी के लिए मैन exec देखें)। – Loki

उत्तर

107

संदेश एक फाइल करने के लिए stdout

exec > file 
stderr

exec > file                  
exec 2>&1 

संलग्न दोनों stdout और stderrदायर करने के लिए साथ

exec >> file 
exec 2>&1 
+7

मैं भी अंत में 2> & 1 जोड़ता हूं कि, बस इतना stderr भी पकड़ा जाता है। :-) –

+1

पश्चिम साल पहले सबसे तेज बंदूक के लिए प्रबुद्ध बैज। – Joshua

+0

आपको पता नहीं है कि मुझे इस तरह से कितने प्रबुद्ध बैज मिले हैं। :- पी –

20

आप पूरी स्क्रिप्ट इस तरह एक समारोह बना सकते हैं:

if [ -z $TERM ]; then 
    # if not run via terminal, log everything into a log file 
    main_function 2>&1 >> /var/log/my_uber_script.log 
else 
    # run via terminal, only output to screen 
    main_function 
fi 

वैकल्पिक रूप से आप लॉगफ़ाइल में सब कुछ लॉग इन कर सकते,:

main_function() { 
    do_things_here 
} 

तो स्क्रिप्ट के अंत में इस राशि प्रत्येक रन और अभी भी इसे केवल आउटपुट द्वारा stdout करने के लिए आउटपुट:

# log everything, but also output to stdout 
main_function 2>&1 | tee -a /var/log/my_uber_script.log 
+0

क्या आप main_function मतलब >> /var/log/my_uber_script.log 2> & 1 –

+0

मैं ऐसे पाइप में main_function का उपयोग कर की तरह। लेकिन इस मामले में आपकी स्क्रिप्ट मूल वापसी मूल्य वापस नहीं करती है। बैश मामले में आपको 'बाहर निकलें $ {PIPESTATUS [0]}' का उपयोग करके बाहर निकलना चाहिए। – rudimeier

87

प्रश्न को अद्यतन के रूप में संबोधित करते हुए।

#...part of script without redirection... 

{ 
    #...part of script with redirection... 
} > file1 2>file2 # ...and others as appropriate... 

#...residue of script without redirection... 

ब्रेसिज़ '{...}' I/O पुनर्निर्देशन की एक इकाई प्रदान करते हैं। ब्रेसिज़ दिखाना चाहिए जहां एक कमांड दिखाई दे सकता है - सरलीकृत रूप से, रेखा की शुरुआत में या सेमी-कोलन के बाद। (हां, यह और अधिक सटीक बनाया जा सकता है, यदि आप वक्रोक्ति करना चाहते हैं, मुझे पता है।)

आप सही है कि आप पुनर्निर्देशन आप से पता चला है के साथ मूल stdout और stderr की रक्षा कर सकते हैं, लेकिन यह आम तौर पर आसान है उन लोगों के लिए जिन्हें बाद में दिखाए गए रीडायरेक्ट कोड को स्कॉप करते हुए क्या हो रहा है, यह समझने के लिए स्क्रिप्ट को बनाए रखना है।

+3

यह मूल वर्णनकर्ताओं को सहेजने और बाद में उन्हें बहाल करने से कहीं अधिक स्पष्ट है। –

+13

मुझे यह समझने के लिए कुछ गुगल करना पड़ा कि यह वास्तव में क्या कर रहा है, इसलिए मैं साझा करना चाहता था। घुंघराले ब्रेसिज़ एक [ "कोड के ब्लॉक"] (http://www.tldp.org/LDP/abs/html/special-chars.html#CODEBLOCKREF) है, जो प्रभाव में, एक _anonymous function_ बनाता हो जाते हैं। कोड ब्लॉक में आउटपुट सब कुछ तब रीडायरेक्ट किया जा सकता है (उस लिंक से ** उदाहरण 3-2 ** देखें)। यह भी ध्यान दें कि घुंघराले ब्रेसिज़ _do not_ लॉन्च नहीं करते हैं [subshell] (http://www.tldp.org/LDP/abs/html/subshells.html), लेकिन समान [I/O रीडायरेक्ट] (http: // www .tldp.org/एलडीपी/abs/html/ioredirintro.html) _can_ कोष्ठक का उपयोग करके सबहेल के साथ किया जाना चाहिए। – chris

+1

मुझे इस समाधान को दूसरों की तुलना में बेहतर पसंद है।यहां तक ​​कि I/O पुनर्निर्देशन की सबसे बुनियादी समझ वाले व्यक्ति को यह भी समझ सकता है कि क्या हो रहा है। इसके अलावा, यह अधिक verbose है। और, एक पायथनर के रूप में, मुझे वर्बोज़ पसंद है। –

2

मूल stdout बचत के लिए और stderr आप का उपयोग कर सकते हैं:

exec [fd number]<&1 
exec [fd number]<&2 

उदाहरण के लिए, निम्नलिखित कोड "walla1" और लॉग फ़ाइल (a.txt) करने के लिए "walla2" प्रिंट होगा, "walla3 "stdout करने के लिए," walla4 "stderr करने के लिए।

#!/bin/bash 

exec 5<&1 
exec 6<&2 

exec 1> ~/a.txt 2>&1 

echo "walla1" 
echo "walla2" >&2 
echo "walla3" >&5 
echo "walla4" >&6 
+1

आम तौर पर आउटपुट के लिए इनपुट रीडायरेक्शन नोटेशन के बजाय आउटपुट रीडायरेक्शन नोटेशन का उपयोग करके 'निष्पादन 5> और 1' और' exec 6> और 2' 'का उपयोग करना बेहतर होगा। आप इससे दूर हो जाते हैं क्योंकि जब स्क्रिप्ट टर्मिनल से चलती है, तो मानक इनपुट भी लिखने योग्य होता है और मानक आउटपुट और मानक त्रुटि दोनों ऐतिहासिक क्विर्क के गुण (या यह 'उपाध्यक्ष') द्वारा पठनीय हैं: टर्मिनल खोला गया है पढ़ना और लिखना और वही [खुली फ़ाइल विवरण] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html) का उपयोग सभी तीन मानक I/O फ़ाइल वर्णनकर्ताओं के लिए किया जाता है। –

संबंधित मुद्दे