bash - बैड स्क्रिप्ट के भीतर से लॉग फ़ाइल करने के लिए stdout की COPY को पुनर्निर्देशित करें




shell redirect (6)

मुझे पता है कि एक फ़ाइल में stdout को पुनर्निर्देशित करने के लिए कैसे:

exec > foo.log
echo test

यह 'test' को foo.log फ़ाइल में डाल देगा।

अब मैं आउटपुट को लॉग फ़ाइल में रीडायरेक्ट करना चाहता हूं और इसे स्टडआउट पर रखना चाहता हूं

यानी इसे स्क्रिप्ट के बाहर से छोटे से किया जा सकता है:

script | tee foo.log

लेकिन मैं इसे स्क्रिप्ट के भीतर ही घोषित करना चाहता हूं

मैंने कोशिश की

exec | tee foo.log

लेकिन यह काम नहीं किया।


Syslog पर बैश स्क्रिप्ट लॉग बनाने का आसान तरीका। स्क्रिप्ट आउटपुट /var/log/syslog माध्यम से और stderr के माध्यम से दोनों उपलब्ध है। syslog टाइमस्टैम्प समेत उपयोगी मेटाडेटा जोड़ देगा।

शीर्ष पर इस पंक्ति को जोड़ें:

exec &> >(logger -t myscript -s)

वैकल्पिक रूप से, लॉग को एक अलग फ़ाइल में भेजें:

exec &> >(ts |tee -a /tmp/myscript.output >&2 )

इसके लिए अधिक moreutils आवश्यकता moreutils ( ts कमांड के लिए, जो टाइमस्टैम्प जोड़ता है)।


अपनी स्क्रिप्ट फ़ाइल के अंदर, सभी आदेशों को कोष्ठक के भीतर रखें, जैसे:

(
echo start
ls -l
echo end
) | tee foo.log

बैश 4 में एक coproc कमांड है जो एक कमांड पर नामित पाइप स्थापित करता है और आपको इसके माध्यम से संवाद करने की अनुमति देता है।


स्वीकार्य उत्तर एसटीडीईआरआर को एक अलग फ़ाइल डिस्क्रिप्टर के रूप में संरक्षित नहीं करता है। इसका मत

./script.sh >/dev/null

टर्मिनल पर आउटपुट bar नहीं, केवल लॉगफाइल के लिए, और

./script.sh 2>/dev/null

टर्मिनल पर foo और bar दोनों आउटपुट करेगा। स्पष्ट रूप से यह व्यवहार नहीं है कि एक सामान्य उपयोगकर्ता की अपेक्षा की जा सकती है। यह एक ही लॉग फ़ाइल में संलग्न दोनों अलग टी प्रक्रियाओं का उपयोग करके तय किया जा सकता है:

#!/bin/bash

# See (and upvote) the comment by JamesThomasMoon1979 
# explaining the use of the -i option to tee.
exec >  >(tee -ia foo.log)
exec 2> >(tee -ia foo.log >&2)

echo "foo"
echo "bar" >&2

(ध्यान दें कि उपर्युक्त प्रारंभ में लॉग फ़ाइल को छोटा नहीं करता है - यदि आप उस व्यवहार को जोड़ना चाहते हैं तो आपको जोड़ना चाहिए

>foo.log

लिपि के शीर्ष पर।)

टीओएसई -1-2008 टीई tee(1) विनिर्देश के लिए आवश्यक है कि आउटपुट अनबफर किया गया हो , यानी लाइन-बफर भी नहीं किया गया है, इसलिए इस मामले में यह संभव है कि STDOUT और STDERR foo.log की एक ही पंक्ति पर समाप्त हो सके; हालांकि यह टर्मिनल पर भी हो सकता है, इसलिए लॉग फ़ाइल टर्मिनल पर जो देखा जा सकता है उसका एक वफादार प्रतिबिंब होगा, अगर इसका सटीक दर्पण नहीं है। यदि आप एसटीडीओआरटी लाइनों को एसटीडीईआरआर लाइनों से साफ़ रूप से अलग करना चाहते हैं, तो दो लॉग फ़ाइलों का उपयोग करने पर विचार करें, संभवतः प्रत्येक पंक्ति पर दिनांक स्टैम्प उपसर्गों के साथ क्रोनोलॉजिकल रीसाइक्लिंग को अनुमति देने के लिए।


व्यस्त बॉक्स और गैर-बैश गोले के लिए समाधान

स्वीकार किए गए उत्तर निश्चित रूप से बैश के लिए सबसे अच्छा विकल्प है। मैं बैश तक पहुंच के बिना एक व्यस्त बॉक्स वातावरण में काम कर रहा हूं, और यह exec > >(tee log.txt) वाक्यविन्यास को समझ में नहीं आता है। यह exec >$PIPE के समान नाम के साथ सामान्य फ़ाइल बनाने की कोशिश कर रहा है, जो ठीक से exec >$PIPE नहीं करता है, जो विफल रहता है और लटकता है।

उम्मीद है कि यह किसी और के लिए उपयोगी होगा जिसके पास बैश नहीं है।

इसके अलावा, नामित पाइप का उपयोग करने वाले किसी भी व्यक्ति के लिए, यह rm $PIPE लिए सुरक्षित है, क्योंकि यह वीएफएस से पाइप को अनलिंक करता है, लेकिन इसका उपयोग करने वाली प्रक्रियाओं को तब तक एक संदर्भ गणना बनाए रखती है जब तक कि वे समाप्त नहीं हो जाते।

ध्यान दें कि $ * का उपयोग जरूरी नहीं है।

#!/bin/sh

if [ "$SELF_LOGGING" != "1" ]
then
    # The parent process will enter this branch and set up logging

    # Create a named piped for logging the child's output
    PIPE=tmp.fifo
    mkfifo $PIPE

    # Launch the child process without redirected to the named pipe
    SELF_LOGGING=1 sh $0 $* >$PIPE &

    # Save PID of child process
    PID=$!

    # Launch tee in a separate process
    tee logfile <$PIPE &

    # Unlink $PIPE because the parent process no longer needs it
    rm $PIPE    

    # Wait for child process running the rest of this script
    wait $PID

    # Return the error code from the child process
    exit $?
fi

# The rest of the script goes here

#!/usr/bin/env bash

# Redirect stdout ( > ) into a named pipe ( >() ) running "tee"
exec > >(tee -i logfile.txt)

# Without this, only stdout would be captured - i.e. your
# log file would not contain any error messages.
# SEE (and upvote) the answer by Adam Spiers, which keeps STDERR
# as a separate stream - I did not want to steal from him by simply
# adding his answer to mine.
exec 2>&1

echo "foo"
echo "bar" >&2

ध्यान दें कि यह bash , नहीं। यदि आप sh myscript.sh साथ स्क्रिप्ट का आह्वान करते हैं, तो आपको syntax error near unexpected token '>' साथ एक त्रुटि मिलेगी।

यदि आप सिग्नल जाल के साथ काम कर रहे हैं, तो आप सिग्नल होने पर आउटपुट के व्यवधान से बचने के लिए tee -i विकल्प का उपयोग करना चाहेंगे। (टिप्पणी के लिए जेम्स थॉमस मून 1 9 7 9 के लिए धन्यवाद।)

उपकरण जो उनके आउटपुट को बदलते हैं, वे एक पाइप या टर्मिनल (उदाहरण के लिए रंगों और स्तंभित आउटपुट का उपयोग करके) लिखते हैं, इस पर निर्भर करते हैं कि उपरोक्त निर्माण का अर्थ यह है कि वे एक पाइप पर आउटपुट करते हैं।

रंगीन / स्तंभकरण को लागू करने के विकल्प हैं (उदाहरण के लिए ls -C --color=always )। ध्यान दें कि इसके परिणामस्वरूप रंग कोड लॉगफाइल पर भी लिखे जा रहे हैं, जिससे इसे कम पठनीय बना दिया जा सकता है।







redirect