मैं स्क्रिप्ट के भीतर संपूर्ण शेल स्क्रिप्ट के आउटपुट को कैसे पुनर्निर्देशित करूं?


205

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

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

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

# rest of script...

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

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

अद्यतन: यहोशू का जवाब हाजिर है, लेकिन मैं पूरी स्क्रिप्ट के बारे में 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
इंटरैक्टिव मोड के लिए परीक्षण करने के लिए $ TERM के लिए परीक्षण सबसे अच्छा तरीका नहीं है। इसके बजाय, परीक्षण करें कि क्या स्टड एक टैटी है (टेस्ट -०)।
क्रिस जस्टर-यंग

2
दूसरे शब्दों में: अगर [! —टी ०]; फिर निष्पादित करें> somefile 2> & 1; फाई
क्रिस जस्टर-यंग

1
सभी अच्छाई के लिए यहां देखें: http://tldp.org/LDP/abs/html/io-redirection.html मूल रूप से जोशुआ द्वारा कहा गया था। exec> file redirects stdout to a specific file, एक्जीक्यूट <file को stdin की जगह file, etc। इसका समान रूप से किया जाता है, लेकिन निष्पादन का उपयोग करते हुए (अधिक विवरण के लिए आदमी का निष्पादन देखें)।
लोकी

अपने अपडेट सेक्शन में, आपको एफडी 3 और 4 को भी बंद करना चाहिए, जैसे: exec 1>&3 2>&4 3>&- 4>&-
गुरजीत सिंह

जवाबों:


173

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

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

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

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

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

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

बैश मैनुअल के संबंधित अनुभाग ग्रुपिंग कमांड और आई / ओ रीडायरेक्शन हैं । POSIX शेल विनिर्देशन के प्रासंगिक अनुभाग कम्पाउंड कमांड और I / O रीडायरेक्शन हैं । बैश में कुछ अतिरिक्त संकेतन हैं, लेकिन अन्यथा POSIX शेल विनिर्देश के समान है।


3
यह मूल विवरणकों को बचाने और बाद में उन्हें पुनर्स्थापित करने की तुलना में बहुत स्पष्ट है।
स्टीव मैडसेन

23
मुझे यह समझने के लिए कुछ गुगली करनी थी कि यह वास्तव में क्या है, इसलिए मैं साझा करना चाहता था। घुंघराले ब्रेसिज़ "कोड का ब्लॉक" बन जाते हैं , जो प्रभाव में, एक अनाम फ़ंक्शन बनाता है । कोड ब्लॉक में आउटपुट सब कुछ तब पुनर्निर्देशित किया जा सकता है ( उस लिंक से उदाहरण 3-2 देखें )। यह भी ध्यान दें कि घुंघराले ब्रेसिज़ एक उपखंड को लॉन्च नहीं करते हैं , लेकिन समान I / O पुनर्निर्देशन अभिभावकों के उपयोग से उपधाराओं के साथ किया जा सकता है।
क्रिस

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

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

यह एप्लिकेशन ccc.bmw71 (.pro) (3C बैटरी मॉनिटर विजेट, पूर्व में "बैटरी मॉनिटर विजेट") हमेशा बैटरी इतिहास को /sdcard/bmw_history.txt पर निर्यात करता है। यदि पहले से मौजूद है, तो अनुमान लगाएं , क्या है ! इसने मुझे कुछ बैटरी इतिहास खो दिया। मैंने 30 से बहुत अधिक दिनों तक सीमा निर्धारित की, जिसने इसे अमान्य कर दिया और इसे वापस 30 पर रख दिया। मैं मौजूदा बैकअप आयात करने से पहले वर्तमान बैटरी इतिहास को निर्यात करना चाहता था। फिर वही हुआ।
neverMind9

175

आमतौर पर हम इनमें से एक को स्क्रिप्ट के शीर्ष पर या उसके समीप रखेंगे। यह बताता है कि उनकी कमांड लाइनों को पार्स करने के बाद पुनर्निर्देशन किया जाएगा।

एक फ़ाइल के लिए stdout भेजें

exec > file

stderr के साथ

exec > file                                                                      
exec 2>&1

फ़ाइल करने के लिए stdout और stderr दोनों संलग्न करें

exec >> file
exec 2>&1

जैसा कि जोनाथन लेफ़लर ने अपनी टिप्पणी में उल्लेख किया है :

execदो अलग-अलग काम हैं। पहला एक वर्तमान में निष्पादित शेल (स्क्रिप्ट) को एक नए कार्यक्रम के साथ बदलना है। दूसरा वर्तमान शेल में I / O पुनर्निर्देशन को बदल रहा है। यह कोई तर्क नहीं होने से प्रतिष्ठित है exec


7
मैं कहता हूं कि उस के अंत में 2> & 1 भी जोड़ें, बस इतना ही स्टैडर भी पकड़ा जाता है। :-)
क्रिस जस्टर-यंग

7
आप इन्हें कहाँ लगाते हैं? स्क्रिप्ट के शीर्ष पर?
कॉलन

4
इस समाधान के साथ किसी को स्क्रिप्ट से बाहर निकलने वाले रीडायरेक्ट को भी रीसेट करना होगा। जोनाथन लेफ़लर द्वारा अगला उत्तर इस अर्थ में अधिक "विफल प्रमाण" है।
चुइम

6
@ जॉन्डर: execकी दो अलग-अलग नौकरियां हैं। एक ही प्रक्रिया का उपयोग करके वर्तमान स्क्रिप्ट को किसी अन्य कमांड के साथ बदलना है - आप अन्य कमांड को एक तर्क के रूप में निर्दिष्ट करते हैं exec(और आप I / O को पुनर्निर्देशित कर सकते हैं जैसा कि आप इसे करते हैं)। अन्य कार्य वर्तमान शेल स्क्रिप्ट में I / O पुनर्निर्देशन को बदले बिना बदल रहा है। इस नोटेशन को एक तर्क के रूप में एक कमांड नहीं होने के द्वारा प्रतिष्ठित किया जाता है exec। इस उत्तर में संकेतन "I / O केवल" प्रकार का है - यह केवल पुनर्निर्देशन को बदलता है और चल रहे स्क्रिप्ट को प्रतिस्थापित नहीं करता है। (यह setआज्ञा समान रूप से बहुउद्देश्यीय है।)
जोनाथन लेफ्लर

18
exec > >(tee -a "logs/logdata.log") 2>&1स्क्रीन पर लॉग को प्रिंट करता है और साथ ही उन्हें एक फाइल में लिखता है
shriyog

32

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

main_function() {
  do_things_here
}

फिर स्क्रिप्ट के अंत में यह है:

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

वैकल्पिक रूप से, आप प्रत्येक रन में लॉगफ़ाइल में सब कुछ लॉग कर सकते हैं और अभी भी इसे केवल स्टडआउट करने के लिए आउटपुट कर सकते हैं:

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

क्या आपका मतलब main_function >> /var/log/my_uber_script.log 2> & 1
फेलिप अल्वारेज़

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

7

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

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

उदाहरण के लिए, निम्न कोड लॉग फ़ाइल के लिए "walla1" और "walla2" को प्रिंट करेगा ( a.txt), "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
आम तौर पर, आउटपुट के लिए इनपुट पुनर्निर्देशन संकेतन के बजाय आउटपुट पुनर्निर्देशन अंकन का उपयोग करना exec 5>&1और उपयोग करना बेहतर होगा exec 6>&2। आप इसके साथ दूर हो जाते हैं क्योंकि जब स्क्रिप्ट को टर्मिनल से चलाया जाता है, तो मानक इनपुट भी लेखन योग्य होता है और दोनों मानक आउटपुट और मानक त्रुटि पुण्य के द्वारा पठनीय होती है (या यह एक ऐतिहासिक क्वर्की का 'वाइस' है): टर्मिनल किसके लिए खोला जाता है? पढ़ना और लिखना और एक ही खुले फ़ाइल विवरण का उपयोग सभी तीन मानक I / O फ़ाइल विवरणकों के लिए किया जाता है।
जोनाथन लेफ़लर

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