बैश में रिडायरेक्टर और स्टडआउट


678

मैं एक प्रक्रिया के stdout और stderr दोनों को एक फ़ाइल में पुनर्निर्देशित करना चाहता हूं। मैं बैश में कैसे करूँ?


2
मैं यह कहना चाहता हूं कि यह आश्चर्यजनक रूप से उपयोगी प्रश्न है। बहुत से लोग यह नहीं जानते हैं कि यह कैसे करना है, क्योंकि उन्हें ऐसा अक्सर नहीं करना पड़ता है, और यह बैश का सबसे अच्छा दस्तावेज नहीं है।
रॉबर्ट Wm Ruedisueli

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

जवाबों:


761

यहां देखिए । होना चाहिए:

yourcommand &>filename

(पुनर्निर्देश दोनों stdoutऔर stderrफ़ाइल नाम के लिए)।


29
यह सिंटेक्स बैश हैकर्स विकी के अनुसार हटा दिया गया है । क्या यह?
सलमान वॉन अब्बास

20
Wiki.bash-hackers.org/scripting/obirect के अनुसार , यह इस अर्थ में अप्रचलित प्रतीत होता है कि यह POSIX का हिस्सा नहीं है, लेकिन बैश मैन पेज निकट भविष्य में इसे बैश से हटाए जाने का कोई उल्लेख नहीं करता है। मैन पेज '&>' ओवर '> और' के लिए वरीयता निर्दिष्ट करता है, जो अन्यथा समकक्ष है।
chepner

13
मुझे लगता है कि हमें POSIX में उपयोग नहीं करना चाहिए और ऐसा नहीं करना चाहिए, और "गोले" जैसे सामान्य गोले इसका समर्थन नहीं करते हैं।
सैम वाटकिंस

27
एक अतिरिक्त संकेत: यदि आप इसे एक स्क्रिप्ट में उपयोग करते हैं, तो सुनिश्चित करें कि यह शुरू होता #!/bin/bashहै #!/bin/sh, बजाय इसके कि बैश की आवश्यकता होती है।
टोर क्लिंगबर्ग

8
ओवरराइट के बजाय या फिर >> अपील करें।
अलेक्जेंडर गोंचिए

448
do_something 2>&1 | tee -a some_file

यह stdout और stdout के लिए stderout को रीडायरेक्ट करने वाला है some_file और इसे stdout में प्रिंट करने के लिए है।


16
AIX (ksh) पर आपका समाधान काम करता है। स्वीकृत उत्तर do_something &>filenameनहीं है। +1।
रोक

11
@ डैनियल, लेकिन यह सवाल विशेष रूप से बैश के बारे में है
जॉन ला रोय

3
मुझे Ambiguous output redirect.कोई भी विचार मिलता है क्यों?
अलेक्जेंड्रे होल्डन डेली

1
मेरे पास एक रूबी स्क्रिप्ट है (जो मैं किसी भी तरह से संशोधित नहीं करना चाहता) जो बोल्ड रेड में त्रुटि संदेशों को प्रिंट करता है। यह रूबी स्क्रिप्ट तब मेरी बैश स्क्रिप्ट (जिसे मैं संशोधित कर सकता हूं) से मंगाई गई है। जब मैं ऊपर का उपयोग करता हूं, तो यह सादे पाठ में त्रुटि संदेशों को प्रिंट करता है, स्वरूपण को घटाता है। क्या ऑन-स्क्रीन फ़ॉर्मेटिंग को बनाए रखने और किसी फ़ाइल में आउटपुट (दोनों stdout और stderr) प्राप्त करने का कोई तरीका है?
एटलांटिस

8
ध्यान दें कि (डिफ़ॉल्ट रूप से) इसका साइड-इफेक्ट है जो $?अब बाहर निकलने की स्थिति को संदर्भित नहीं करता है do_something, लेकिन बाहर निकलने की स्थिति tee
फ्लिम

255

आप अनुप्रेषित कर सकते हैं stderr करने के लिए stdout और stdout एक फ़ाइल में:

some_command >file.log 2>&1 

Http://tldp.org/LDP/abs/html/io-redirection.html देखें

यह प्रारूप सबसे लोकप्रिय और> प्रारूप से अधिक पसंद किया जाता है जो केवल बैश में काम करता है। बॉर्न शेल में इसे पृष्ठभूमि में कमांड चलाने के रूप में व्याख्या किया जा सकता है। साथ ही प्रारूप अधिक पठनीय 2 है (STDERR) 1 (STDOUT) पर पुनर्निर्देशित।

EDIT: टिप्पणियों में बताए गए क्रम को बदल दिया


47
यह मूल stdout में stderr को रीडायरेक्ट करता है, न कि उस फ़ाइल पर जहाँ stdout जा रही है। '> File.log' के बाद '2> & 1' डालें और यह काम करता है।

1
इस दृष्टिकोण का कुछ_कम और> file.log पर क्या लाभ है?
ubermonkey

6
यदि आप किसी फ़ाइल में संलग्न करना चाहते हैं, तो आपको इसे इस तरह करना होगा: इको "फू" 2> & 1 1 >> bar.txt AFAIK का उपयोग करने और अपेंड करने का कोई तरीका नहीं है
SlappyTheFish

9
अर्ग, सॉरी, गूंज "फू" 1 >> bar.txt 2> & 1
SlappyTheFish

11
मुझे लगता है कि 2> और 1 पुनर्निर्देशन stdout करने के लिए stderr गलत है; मेरा मानना ​​है कि यह कहना अधिक सटीक है कि यह उसी स्थान पर stderr भेजता है जहां stdout इस समय चल रहा है। इस प्रकार पहली रीडायरेक्ट आवश्यक होने के बाद 2> & 1 रखें ।
jdg

201
# Close STDOUT file descriptor
exec 1<&-
# Close STDERR FD
exec 2<&-

# Open STDOUT as $LOG_FILE file for read and write.
exec 1<>$LOG_FILE

# Redirect STDERR to STDOUT
exec 2>&1

echo "This line will appear in $LOG_FILE, not 'on screen'"

अब, सरल गूंज $ LOG_FILE को लिखेंगे। निस्तारण के लिए उपयोगी है।

मूल पोस्ट के लेखक के लिए,

यह निर्भर करता है कि आपको क्या हासिल करना है। यदि आपको अपनी स्क्रिप्ट से कॉल करने वाली किसी कमांड के अंदर / बाहर अनुप्रेषित करने की आवश्यकता है, तो उत्तर पहले ही दिए जा चुके हैं। मेरा वर्तमान स्क्रिप्ट के भीतर पुनर्निर्देशन के बारे में है जो उल्लिखित कोड स्निपेट के बाद सभी कमांड / बिल्ट-इन (फोर्क शामिल हैं) को प्रभावित करता है।


एक और अच्छा समाधान एसटीडी-इर / आउट दोनों को रीडायरेक्ट करने के बारे में है और एक बार में लकड़हारा या लॉग फाइल करने के लिए जिसमें "स्ट्रीम" को दो में विभाजित करना शामिल है। यह कार्यक्षमता 'टी' कमांड द्वारा प्रदान की जाती है, जो एक साथ कई फाइल डिस्क्रिप्टर (फाइल, सॉकेट, पाइप आदि) को लिख / जोड़ सकती है: Tee FILE1 FILE2 ...> (cmd1)> (cmd2) ...

exec 3>&1 4>&2 1> >(tee >(logger -i -t 'my_script_tag') >&3) 2> >(tee >(logger -i -t 'my_script_tag') >&4)
trap 'cleanup' INT QUIT TERM EXIT


get_pids_of_ppid() {
    local ppid="$1"

    RETVAL=''
    local pids=`ps x -o pid,ppid | awk "\\$2 == \\"$ppid\\" { print \\$1 }"`
    RETVAL="$pids"
}


# Needed to kill processes running in background
cleanup() {
    local current_pid element
    local pids=( "$$" )

    running_pids=("${pids[@]}")

    while :; do
        current_pid="${running_pids[0]}"
        [ -z "$current_pid" ] && break

        running_pids=("${running_pids[@]:1}")
        get_pids_of_ppid $current_pid
        local new_pids="$RETVAL"
        [ -z "$new_pids" ] && continue

        for element in $new_pids; do
            running_pids+=("$element")
            pids=("$element" "${pids[@]}")
        done
    done

    kill ${pids[@]} 2>/dev/null
}

तो, शुरू से। मान लें कि हमारे पास / dev / stdout (FD # 1) और / dev / stderr (FD # 2) से जुड़ा टर्मिनल है। व्यवहार में, यह एक पाइप, सॉकेट या जो कुछ भी हो सकता है।

  • एफडी # 3 और # 4 बनाएं और क्रमशः "1" और # 2 के समान "स्थान" को इंगित करें। एफडी # 1 बदलने से अब से एफडी # 3 प्रभावित नहीं होता है। अब, FD # 3 और # 4 क्रमशः STDOUT और STDERR को इंगित करते हैं। इन्हें वास्तविक टर्मिनल STDOUT और STDERR के रूप में उपयोग किया जाएगा ।
  • 1>> (...) Parens में कमांड को STDOUT रीडायरेक्ट करता है
  • parens (सब-शेल) निष्पादन के STDOUT (पाइप) से 'टी' रीडिंग को निष्पादित करता है और parens में सब-शेल के लिए एक अन्य पाइप के माध्यम से 'लकड़हारा' कमांड को रीडायरेक्ट करता है। उसी समय यह उसी इनपुट को FD # 3 (टर्मिनल) में कॉपी करता है
  • दूसरा भाग, बहुत समान, एसटीडीआर और एफडी # 2 और # 4 के लिए एक ही चाल करने के बारे में है।

उपरोक्त पंक्ति वाली स्क्रिप्ट को चलाने का परिणाम और इसके अतिरिक्त यह:

echo "Will end up in STDOUT(terminal) and /var/log/messages"

...इस प्रकार है:

$ ./my_script
Will end up in STDOUT(terminal) and /var/log/messages

$ tail -n1 /var/log/messages
Sep 23 15:54:03 wks056 my_script_tag[11644]: Will end up in STDOUT(terminal) and /var/log/messages

यदि आप स्पष्ट चित्र देखना चाहते हैं, तो इन 2 पंक्तियों को स्क्रिप्ट में जोड़ें:

ls -l /proc/self/fd/
ps xf

1
केवल एक अपवाद। पहले उदाहरण में आपने लिखा था: 1 <> $ LOG_FILE। यह मूल लॉगफाइल का कारण बनता है, जो कि सर्वव्यापी है। असली लॉगगिन के लिए बेहतर तरीका है: निष्पादन 1 >> $ लोग_इजर्स जिसके कारण लॉग लॉग किया गया है।
ज़नीक डे

4
यह सच है, हालांकि यह इरादों पर निर्भर करता है। मेरा दृष्टिकोण हमेशा एक अद्वितीय और टाइमस्टैम्प्ड लॉग फ़ाइल बनाना है। दूसरे को जोड़ना है। दोनों तरीके 'लॉगरोटेबल' हैं। मैं अलग-अलग फ़ाइलों को पसंद करता हूं, जिन्हें कम पार्सिंग की आवश्यकता होती है, लेकिन जैसा कि मैंने कहा, जो भी आपकी नाव चल रही है :)
क्विज़ैक

1
आपका दूसरा समाधान जानकारीपूर्ण है, लेकिन सभी सफाई कोड के साथ क्या है? यह प्रासंगिक नहीं लगता है, और यदि हां, तो केवल एक अच्छा उदाहरण है। मैं यह भी देखना चाहता हूं कि इसे थोड़ा ठीक किया जाए ताकि एफडी 1 और 2 को लकड़हारे तक न पहुँचाया जाए, बल्कि 3 और 4 इसलिए हैं कि इस स्क्रिप्ट को कॉल करने वाली कोई भी चीज़ 1 और 2 को जोड़ सकती है और आम धारणा के तहत आगे पीछे हो सकती है == 1 और stderr == 2, लेकिन मेरा संक्षिप्त प्रयोग बताता है कि यह अधिक जटिल है।
JFlo

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

1
मैं क्लीन-अप कोड पर विस्तार करना चाहता था। यह स्क्रिप्ट का एक हिस्सा है जो एर्गोमेनेट करता है जो हेंग-यूपी सिग्नल के लिए प्रतिरक्षा बन जाता है। log टी ’और ger लकड़हारा’ एक ही PPID द्वारा प्रायोजित प्रक्रियाएं हैं और वे मुख्य bash स्क्रिप्ट से HUP जाल प्राप्त करते हैं। इसलिए, एक बार जब मुख्य प्रक्रिया मर जाती है तो वे init [1] से विरासत में मिलते हैं। वे लाश नहीं बनेंगे (अशुद्ध) क्लीन-अप कोड सुनिश्चित करता है कि सभी पृष्ठभूमि कार्य मारे गए हैं, अगर मुख्य स्क्रिप्ट मर जाती है। यह किसी अन्य प्रक्रिया पर भी लागू होता है जो संभवतः पृष्ठभूमि में बनाई और चल रही हो।
प्रश्नोत्तरी 24

41
bash your_script.sh 1>file.log 2>&1

1>file.logशेल को फ़ाइल में STDOUT भेजने का निर्देश देता है file.log, और2>&1 इसे STDERR (फ़ाइल डिस्क्रिप्टर 2) को STDOUT (फ़ाइल डिस्क्रिप्टर 1) पर पुनर्निर्देशित करने के लिए कहता है।

नोट: आदेश liw.fi के रूप में मायने रखता है, 2>&1 1>file.logकाम नहीं करता है।


21

उत्सुकता से, यह काम करता है:

yourcommand &> filename

लेकिन यह एक सिंटैक्स त्रुटि देता है:

yourcommand &>> filename
syntax error near unexpected token `>'

आपको उपयोग करना होगा:

yourcommand 1>> filename 2>&1

10
&>>BASH 4 पर काम करने लगता है:$ echo $BASH_VERSION 4.1.5(1)-release $ (echo to stdout; echo to stderr > /dev/stderr) &>> /dev/null
user272735

15

संक्षिप्त उत्तर: Command >filename 2>&1याCommand &>filename


स्पष्टीकरण:

निम्नलिखित कोड पर विचार करें जो शब्द "stdout" को stdout और "stderror" को stderror के लिए प्रिंट करता है।

$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror

ध्यान दें कि 'एंड' ऑपरेटर बैश बताता है कि 2 एक फाइल डिस्क्रिप्टर है (जो स्टॉडर को इंगित करता है) और फाइल का नाम नहीं है। यदि हमने 'और' छोड़ दिया है, तो यह कमांड stdoutstdout में प्रिंट हो जाएगी , और "2" नामक एक फाइल बनाकर लिख देगाstderror वहां लिखेगी।

ऊपर दिए गए कोड के साथ प्रयोग करके, आप खुद देख सकते हैं कि रीडायरेक्शन ऑपरेटर कैसे काम करते हैं। उदाहरण के लिए, कौन सी फाइल को बदलकर, दोनों डिस्क्रिप्टर में से कौन सी कोड की निम्नलिखित दो पंक्तियों 1,2को रीडायरेक्ट किया जाता /dev/nullहै, स्टडआउट से सबकुछ हटा दें, और क्रमशः स्टायरर से सब कुछ (प्रिंटिंग जो बनी हुई है)।

$ (echo "stdout"; echo "stderror" >&2) 1>/dev/null
stderror
$ (echo "stdout"; echo "stderror" >&2) 2>/dev/null
stdout

अब, हम बता सकते हैं कि निम्न कोड क्यों समाधान का उत्पादन करता है:

(echo "stdout"; echo "stderror" >&2) >/dev/null 2>&1

इसे वास्तव में समझने के लिए, मैं आपको फ़ाइल डिस्क्रिप्टर तालिकाओं पर इस वेबपृष्ठ को पढ़ने की अत्यधिक सलाह देता हूं । यह मानते हुए कि आपने पढ़ा है, हम आगे बढ़ सकते हैं। ध्यान दें कि बैश प्रक्रियाएं दाएं से बाएं; इस प्रकार बैश >/dev/nullपहले देखता है (जो समान है 1>/dev/null), और स्टडआउट के बजाय फ़ाइल डिस्क्रिप्टर 1 को / dev / null को इंगित करने के लिए सेट करता है। ऐसा करने के बाद, बैश फिर दाईं ओर बढ़ता है और देखता है 2>&1। यह फ़ाइल डिस्क्रिप्टर 2 को फ़ाइल डिस्क्रिप्टर 1 के समान फ़ाइल को इंगित करने के लिए सेट करता है (और वर्णनकर्ता 1 को स्वयं फ़ाइल नहीं करने के लिए !!!!) ( इस संसाधन को संकेत पर देखें)अधिक जानकारी के लिए)) । चूँकि फ़ाइल डिस्क्रिप्टर 1 अंक / देव / नल के लिए, और फ़ाइल डिस्क्रिप्टर 2 फ़ाइल डिस्क्रिप्टर 1 के रूप में एक ही फ़ाइल के लिए, फ़ाइल डिस्क्रिप्टर 2 अब भी / देव / अशक्त को इंगित करता है। इस प्रकार दोनों फ़ाइल डिस्क्रिप्टर / देव / नल की ओर इशारा करते हैं, और यही कारण है कि कोई आउटपुट प्रदान नहीं किया गया है।


परीक्षण करने के लिए यदि आप वास्तव में अवधारणा को समझते हैं, तो आउटपुट का अनुमान लगाने का प्रयास करें जब हम पुनर्निर्देशन क्रम को बदलते हैं:

(echo "stdout"; echo "stderror" >&2)  2>&1 >/dev/null

stderror

यहाँ तर्क यह है कि बाएं से दाएं का मूल्यांकन, बैश 2> और 1 को देखता है, और इस प्रकार फ़ाइल डिस्क्रिप्टर 1 को उसी स्थान पर इंगित करने के लिए सेट करता है जैसे फ़ाइल डिस्क्रिप्टर 1, यानी स्टडआउट। इसके बाद फ़ाइल डिस्क्रिप्टर 1 (याद रखें कि> / dev / null = 1> / dev / null) को इंगित करने के लिए> / dev / null सेट करता है, इस प्रकार वह सब कुछ हटा दिया जाता है जो आमतौर पर मानक से बाहर भेजा जाता है। इस प्रकार हम सभी के साथ छोड़ दिया गया है जो कि उपधारा (कोष्ठकों में कोड) - यानी "stderror" में stdout को नहीं भेजा गया था। ध्यान देने वाली बात यह है कि भले ही 1 केवल stdout का एक संकेतक है, लेकिन 2 से 1 के माध्यम से सूचक को पुनर्निर्देशित करने से बिंदु 2 की 2>&1श्रृंखला नहीं बनती है -> 1 -> stdout। यदि ऐसा किया गया, तो कोड को 1 / dev / null पर पुनर्निर्देशित करने के परिणामस्वरूप2>&1 >/dev/null पॉइंटर चेन 2 -> 1 -> / dev / null देगा, और इस प्रकार कोड कुछ भी उत्पन्न नहीं करेगा, इसके विपरीत जो हमने ऊपर देखा है।


अंत में, मैं यह नोट करूंगा कि ऐसा करने का एक सरल तरीका है:

यहां खंड 3.6.4 से , हम देखते हैं कि हम ऑपरेटर &>का उपयोग स्टडआउट और स्टडर दोनों को पुनर्निर्देशित करने के लिए कर सकते हैं । इस प्रकार, किसी भी कमांड के stderr और stdout आउटपुट \dev\null(जो आउटपुट को हटाता है) दोनों को रीडायरेक्ट करने के लिए , हम केवल $ command &> /dev/null उदाहरण के मामले में टाइप करते हैं या करते हैं:

$ (echo "stdout"; echo "stderror" >&2) &>/dev/null

चाबी छीन लेना:

  • फ़ाइल डिस्क्रिप्टर पॉइंटर्स की तरह व्यवहार करते हैं (हालांकि फ़ाइल डिस्क्रिप्टर फ़ाइल पॉइंटर्स के समान नहीं हैं)
  • एक फ़ाइल डिस्क्रिप्टर "a" को एक फाइल डिस्क्रिप्टर "b" पर पुनर्निर्देशित करना जो "f" फाइल करने के लिए इंगित करता है, फ़ाइल डिस्क्रिप्टर "a" को एक ही स्थान पर फ़ाइल डिस्क्रिप्टर b - फ़ाइल "f" के रूप में इंगित करता है। यह बिंदुओं की श्रृंखला नहीं बनाता है -> बी -> एफ
  • उपरोक्त के कारण, आदेश मायने रखता 2>&1 >/dev/nullहै,! = है >/dev/null 2>&1। एक आउटपुट उत्पन्न करता है और दूसरा नहीं करता है!

अंत में इन महान संसाधनों पर एक नज़र डालें:

रीडायरेक्शन पर बैश डॉक्यूमेंटेशन , फाइल डिस्क्रिप्टर टेबल्स की व्याख्या , पॉइंटर्स का परिचय


फ़ाइल डिस्क्रिप्टर (0, 1, 2) टेबल में सिर्फ ऑफ़सेट हैं। जब 2> & 1 का उपयोग किया जाता है तो प्रभाव एफडी [2] = डुप (1) होता है, इसलिए जहां भी एफडी [1] एफडी को इंगित कर रहा था [2] अब इंगित करता है। जब आप FD [1] को इंगित करने के लिए / dev / null को बदलते हैं, तो FD [1] को बदल दिया जाता है, लेकिन यह FD [2] स्लॉट (जो stdout को इंगित करता है) नहीं बदलता है। मैं डिप () शब्द का उपयोग करता हूं क्योंकि यह सिस्टम कॉल है जिसका उपयोग फाइल डिस्क्रिप्टर की नकल करने के लिए किया जाता है।
पेट्स

11
LOG_FACILITY="local7.notice"
LOG_TOPIC="my-prog-name"
LOG_TOPIC_OUT="$LOG_TOPIC-out[$$]"
LOG_TOPIC_ERR="$LOG_TOPIC-err[$$]"

exec 3>&1 > >(tee -a /dev/fd/3 | logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_OUT" )
exec 2> >(logger -p "$LOG_FACILITY" -t "$LOG_TOPIC_ERR" )

यह संबंधित है: sdlog को stdOut और stderr लिखना।

यह लगभग काम करता है, लेकिन xinted से नहीं ;;


मुझे लगता है कि यह "/ dev / fd / 3 अनुमति से इनकार करने के कारण काम नहीं करता है"। > & 3 में बदलने से मदद मिल सकती है।
प्रश्नोत्तरी

6

मैं एक समाधान चाहते थे कि स्टडआउट प्लस स्टडर से आउटपुट लॉग फाइल में लिखा जाए और स्टॉडर कंसोल पर अभी भी है। इसलिए मुझे टी के माध्यम से स्टैडर आउटपुट को डुप्लिकेट करने की आवश्यकता थी।

यह समाधान है जो मैंने पाया:

command 3>&1 1>&2 2>&3 1>>logfile | tee -a logfile
  • सबसे पहले स्टैडर और स्टडआउट को स्वैप करें
  • तब लॉग फ़ाइल में स्टडआउट संलग्न करें
  • पाइप stderr टी करने के लिए और यह भी लॉग फाइल करने के लिए संलग्न करें

BTW, यह मेरे लिए काम नहीं किया (logfile खाली है)। | टी का कोई प्रभाव नहीं है। इसके बजाय मैं इसे का उपयोग कर काम कर मिल गया stackoverflow.com/questions/692000/...
यारोस्लाव Bulatov

4

स्थिति के लिए, जब "पाइपिंग" आवश्यक हो तो आप उपयोग कर सकते हैं:

| और

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

echo -ne "15\n100\n"|sort -c |& tee >sort_result.txt

या

TIMEFORMAT=%R;for i in `seq 1 20` ; do time kubectl get pods |grep node >>js.log  ; done |& sort -h

यह बैश-आधारित समाधान STDOUT और STDERR को अलग-अलग ("सॉर्ट -c" के STDERR से या STDERR से "सॉर्ट -h" तक) पाइप कर सकते हैं।


1

"सबसे आसान" तरीका (केवल बाश 4) ls * 2>&- 1>&-:।


1

निम्न कार्यों का उपयोग बीट्वेन स्टडआउट / स्टडर और एक लॉगफाइल आउटपुट टॉगल करने की प्रक्रिया को स्वचालित करने के लिए किया जा सकता है।

#!/bin/bash

    #set -x

    # global vars
    OUTPUTS_REDIRECTED="false"
    LOGFILE=/dev/stdout

    # "private" function used by redirect_outputs_to_logfile()
    function save_standard_outputs {
        if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
            exit 1;
        fi
        exec 3>&1
        exec 4>&2

        trap restore_standard_outputs EXIT
    }

    # Params: $1 => logfile to write to
    function redirect_outputs_to_logfile {
        if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
            exit 1;
        fi
        LOGFILE=$1
        if [ -z "$LOGFILE" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"

        fi
        if [ ! -f $LOGFILE ]; then
            touch $LOGFILE
        fi
        if [ ! -f $LOGFILE ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
            exit 1
        fi

        save_standard_outputs

        exec 1>>${LOGFILE%.log}.log
        exec 2>&1
        OUTPUTS_REDIRECTED="true"
    }

    # "private" function used by save_standard_outputs() 
    function restore_standard_outputs {
        if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: Cannot restore standard outputs because they have NOT been redirected"
            exit 1;
        fi
        exec 1>&-   #closes FD 1 (logfile)
        exec 2>&-   #closes FD 2 (logfile)
        exec 2>&4   #restore stderr
        exec 1>&3   #restore stdout

        OUTPUTS_REDIRECTED="false"
    }

स्क्रिप्ट के अंदर उपयोग का उदाहरण:

echo "this goes to stdout"
redirect_outputs_to_logfile /tmp/one.log
echo "this goes to logfile"
restore_standard_outputs 
echo "this goes to stdout"

जब मैं आपके कार्यों का उपयोग करता हूं और यह मानक आउटपुट को पुनर्स्थापित करने का प्रयास करता है जो मुझे मिलता है गूंज: लेखन त्रुटि: खराब फ़ाइल नंबर रीडायरेक्ट पूरी तरह से काम करता है ... पुनर्स्थापना के लिए प्रतीत नहीं होता है
थोम शूमेचर

आपकी स्क्रिप्ट को काम करने के लिए मुझे इन पंक्तियों पर टिप्पणी करनी थी और मैंने क्रम बदल दिया: #exec 1> & - #closes FD 1 (logfile) #exec 2> & - #closes FD 2 (logfile); निष्पादन 1> & 3 # श्रेष्ठ स्टैडआउट निष्पादन 2> और 4 # श्रेष्ठ स्टॉडर
थोम शूमचर

ऐसा सुनने के लिए क्षमा करें। CentOS 7, bash 4.2.46 में चलने पर मुझे कोई त्रुटि नहीं मिलती है। मैंने उन संदर्भों को एनोटेट किया है जहां मुझे वे आदेश मिले हैं। यह है: Ref: logan.tw/posts/2016/02/20/open-and-close-files-in-bash
फर्नांडो Fabreti

मैं इन आज्ञाओं को AIX पर चला रहा हूं, शायद इसीलिए। मैंने जो ठीक किया उसके लिए मैंने एक पोस्ट जोड़ी।
थॉमस शूमाकर

1

@ फर्नांडो-fabreti

आपने जो कुछ भी किया, उसे जोड़कर मैंने कार्यों को थोड़ा बदल दिया और & - क्लोजिंग को हटा दिया और यह मेरे लिए काम कर गया।

    function saveStandardOutputs {
      if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
        exec 3>&1
        exec 4>&2
        trap restoreStandardOutputs EXIT
      else
          echo "[ERROR]: ${FUNCNAME[0]}: Cannot save standard outputs because they have been redirected before"
          exit 1;
      fi
  }

  # Params: $1 => logfile to write to
  function redirectOutputsToLogfile {
      if [ "$OUTPUTS_REDIRECTED" == "false" ]; then
        LOGFILE=$1
        if [ -z "$LOGFILE" ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: logfile empty [$LOGFILE]"
        fi
        if [ ! -f $LOGFILE ]; then
            touch $LOGFILE
        fi
        if [ ! -f $LOGFILE ]; then
            echo "[ERROR]: ${FUNCNAME[0]}: creating logfile [$LOGFILE]"
            exit 1
        fi
        saveStandardOutputs
        exec 1>>${LOGFILE}
        exec 2>&1
        OUTPUTS_REDIRECTED="true"
      else
        echo "[ERROR]: ${FUNCNAME[0]}: Cannot redirect standard outputs because they have been redirected before"
          exit 1;
      fi
  }
  function restoreStandardOutputs {
      if [ "$OUTPUTS_REDIRECTED" == "true" ]; then
      exec 1>&3   #restore stdout
      exec 2>&4   #restore stderr
      OUTPUTS_REDIRECTED="false"
     fi
  }
  LOGFILE_NAME="tmp/one.log"
  OUTPUTS_REDIRECTED="false"

  echo "this goes to stdout"
  redirectOutputsToLogfile $LOGFILE_NAME
  echo "this goes to logfile"
  echo "${LOGFILE_NAME}"
  restoreStandardOutputs 
  echo "After restore this goes to stdout"

1

ऐसी स्थितियों में जब आप चीजों का उपयोग करने पर विचार करते हैं जैसे exec 2>&1मुझे पढ़ना आसान लगता है यदि संभव हो तो कोड को इस तरह से उपयोग करके पुन: लिखना संभव है:

function myfunc(){
  [...]
}

myfunc &>mylog.log

0

Tcsh के लिए, मुझे निम्नलिखित कमांड का उपयोग करना होगा:

command >& file

यदि उपयोग किया जाता है command &> file, तो यह "अमान्य नल कमांड" त्रुटि देगा।

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