फ़ाइल और कंसोल लॉग करने के लिए आउटपुट लेखन


99

यूनिक्स शेल में, मेरे पास एक env फ़ाइल है ( env फ़ाइल लॉग फ़ाइल नाम और पथ की तरह उपयोगकर्ता स्क्रिप्ट चलाने के लिए आवश्यक मापदंडों को परिभाषित करती है, फ़ाइल को लॉग इन करने के लिए आउटपुट और त्रुटियों को पुनर्निर्देशित करती है, डेटाबेस कनेक्शन विवरण, आदि ) जो सभी आउटपुट को पुनर्निर्देशित करता है ( गूंज संदेश ) और निम्न कोड का उपयोग करके निष्पादित स्क्रिप्ट से लॉग फ़ाइल में त्रुटियां:

exec 1>>${LOG_FILE}
exec 2>>${LOG_FILE}

प्रत्येक स्क्रिप्ट की शुरुआत में env फ़ाइल निष्पादित की जाती है। Env फ़ाइल में उपरोक्त कोड के कारण सभी कंसोल आउटपुट जो उपयोगकर्ता आउटपुट हो सकते हैं या त्रुटियां सीधे लॉग फ़ाइल में आउटपुट हो सकती हैं जो वास्तव में आवश्यक है।

लेकिन कुछ चयनात्मक उपयोगकर्ता आउटपुट हैं जो मैं कंसोल और लॉग फ़ाइल दोनों में प्रदर्शित करना चाहता हूं। लेकिन उपरोक्त कोड के कारण मैं ऐसा नहीं कर पा रहा हूं।

मुझे पता है कि अगर मैं उपरोक्त कोड निकालता हूं तो मुझे इस मामले के लिए वांछित परिणाम मिल सकता है, लेकिन मुझे मैन्युअल रूप से लॉग फाइल में अन्य सभी आउटपुट लिखना होगा जो कि एक आसान काम नहीं है।

क्या उपरोक्त कोड को हटाए बिना कंसोल और लॉग फ़ाइल में आउटपुट प्राप्त करने का कोई तरीका है?

जवाबों:


106
exec 3>&1 1>>${LOG_FILE} 2>&1

लॉग फ़ाइल में stdout और stderr आउटपुट भेजेगा, लेकिन कंसोल से जुड़े fd 3 के साथ आपको भी छोड़ देगा, इसलिए आप ऐसा कर सकते हैं

echo "Some console message" 1>&3

केवल कंसोल के लिए एक संदेश लिखने के लिए, या

echo "Some console and log file message" | tee /dev/fd/3

कंसोल और लॉग फ़ाइल दोनों को संदेश लिखने के लिए - अपने आउटपुट को अपने स्वयं के fd 1 (जो यहां है ) को भेजता है और जिस फ़ाइल को आपने इसे लिखने के लिए कहा था (जो यहाँ fd 3 है, यानी कंसोल)।teeLOG_FILE

उदाहरण:

exec 3>&1 1>>${LOG_FILE} 2>&1

echo "This is stdout"
echo "This is stderr" 1>&2
echo "This is the console (fd 3)" 1>&3
echo "This is both the log and the console" | tee /dev/fd/3

छपता था

This is the console (fd 3)
This is both the log and the console

कंसोल पर और डाल दिया

This is stdout
This is stderr
This is both the log and the console

लॉग फ़ाइल में।


2
जैसा आपने सुझाव दिया वैसा ही काम किया। लेकिन मुझे टी / देव / fd / 3 समझ में नहीं आया । मुझे पता है कि टी लॉग फ़ाइल और कंसोल के लिए संदेश लिखता है, लेकिन मैं वास्तव में / देव / fd / 3 को टी के बाद इस्तेमाल नहीं समझता
abinash shrestha

@ अंश यह टी का एक असामान्य उपयोग है, मैं सहमत हूं। /dev/fd/3एक फ़ाइल नाम है कि "वर्तमान में खुले fd 3" को संदर्भित करता है, इसलिए tee /dev/fd/3जो कुछ भी अपने stdin पर आता है 1 fd को लिखने और यह भी 3 (FD जाएगा /dev/fd/3फ़ाइल)। Fd 1 लॉग फ़ाइल से जुड़ा है, fd 3 कंसोल से जुड़ा है।
इयान रॉबर्ट्स

इसके अलावा, आप केवल एक फ़ाइल में लिखना चाहते हैं, न कि कंसोल की कोशिश: echo "blah" | tee file1.txt | tee file2.txt >/dev/null 'Blah' को file1.txt और file2.txt में नहीं डाला जाएगा, लेकिन कंसोल पर नहीं लिखा जाएगा।
खतरे '

यह मेरे लिए बहुत मददगार था। हालाँकि मैंने कुछ ऐसा देखा है जो विषय से हटकर हो सकता है लेकिन शायद आप में से कुछ लोग इसके कारणों को जानते हैं। Im बैश स्क्रिप्ट से R स्क्रिप्ट निष्पादित कर रहा है। विभिन्न आर कार्यों का कंसोल आउटपुट रंगीन है (जैसा कि मैंने इसे परिभाषित किया है)। कंसोल और लॉगफ़ाइल के आउटपुट को रीडायरेक्ट करने के लिए उपरोक्त दृष्टिकोण का उपयोग करते समय, कंसोल आउटपुट अब रंगीन नहीं है। उसका क्या कारण हो सकता है?
डाईहेलस्टे

1
@dieHellste कुछ प्रोग्राम यह पता लगाने में सक्षम होते हैं कि उनका आउटपुट किसी अन्य प्रक्रिया (इस मामले में tee, जो बदले में टर्मिनल को लिखता है) के बजाय सीधे एक टर्मिनल पर जा रहा है, और मैच के लिए अपने आउटपुट को समायोजित कर सकता है।
इयान रॉबर्ट्स

43

हाँ, आप उपयोग करना चाहते हैं tee:

टी - मानक इनपुट से पढ़ें और मानक आउटपुट और फ़ाइलों को लिखें

बस अपनी कमांड को टी करने और फाइल को एक तर्क के रूप में पास करने के लिए, जैसे:

exec 1 | tee ${LOG_FILE}
exec 2 | tee ${LOG_FILE}

यह दोनों आउटपुट को STDOUT में प्रिंट करता है और समान आउटपुट को लॉग फ़ाइल में लिखता है। man teeअधिक जानकारी के लिए देखें ।

ध्यान दें कि यह लॉग फ़ाइल में stderr नहीं लिखेगा, इसलिए यदि आप दो धाराओं को संयोजित करना चाहते हैं तो उपयोग करें:

exec 1 2>&1 | tee ${LOG_FILE}

2
उपरोक्त समाधान से काम नहीं चला। मेरे पास redirect.env फ़ाइल है: ##### redirect.env ###### निर्यात LOG_FILE = log.txt निष्पादन 1 2> और 1 | टी-ए $ {LOG_FILE} निष्पादन 1 | tee -a $ {LOG_FILE} exec 2 | tee -a $ {LOG_FILE} ######### और कार्यशील फ़ाइल में निम्नलिखित कोड होते हैं: ##### output.sh ##### #! / bin / sh। redirect.env इको "Valid output" ech "अमान्य आउटपुट" ############## लेकिन मुझे त्रुटि मिलती है: #### redirect.env: पंक्ति 3: निष्कासन: 1 redirect.env: पंक्ति 5: exec: 1: नहीं मिला redirect.env: पंक्ति 6: निष्पादन: 2: #### नहीं मिला है और लॉग फ़ाइल में मुझे भी वही त्रुटि मिलती है। क्या मैं गलत हूं?
अविनाश श्री

यह बताना बहुत कठिन है, क्योंकि आपकी टिप्पणी में नई लाइनें छीन ली गई हैं। आप की तरह कहीं पर कोड का पेस्ट किया जा सका सार ?
जॉन केयर्न्स

1
मैंने फ़ाइलों को लिंक UnixRedirect में जोड़ा है । संबंधित फाइलें redirect.env और output.sh
abinash shrestha

1
यह कोड काम नहीं कर रहा है (कम से कम कोई और नहीं)। आप आमतौर script.sh: line 5: exec: 1: not found
tftd

39

मैंने जॉनी के जवाब की कोशिश की, लेकिन मुझे भी मिल गया

निष्पादन: 1: नहीं मिला

त्रुटि। यह मेरे लिए सबसे अच्छा काम करता है ( zsh में भी काम करने की पुष्टि ):

#!/bin/bash
LOG_FILE=/tmp/both.log
exec > >(tee ${LOG_FILE}) 2>&1
echo "this is stdout"
chmmm 77 /makeError

फ़ाइल /tmp/both.log बाद में होती है

this is stdout
chmmm command not found 

/Tmp/both.log को तब तक जोड़ा जाता है जब तक कि आप -a को टी से हटा नहीं देते हैं।

संकेत: >(...)एक प्रक्रिया प्रतिस्थापन है। यह सुविधा देता है execके लिए teeके रूप में अगर यह एक फ़ाइल थे आदेश।


1
यह मेरे लिए एक आकर्षण की तरह काम करता है, जबकि अन्य उत्तर हिट या मिस हो गए हैं।
जे टेलर

इस स्निपेट को साझा करने के लिए धन्यवाद। यह ठीक काम करने लगता है (अन्य उत्तरों की तुलना में)!
tftd 16

यह काम करता है, लेकिन अब निष्पादन के बाद मेरा खोल अलग है।
जोश उस्रे

@JoshUsre यदि आप कोई सहायता चाहते हैं या आप अन्य SO-उपयोगकर्ताओं की मदद करना चाहते हैं, तो कृपया बताएं कि क्या अलग है, और अपने शेल, संस्करण, OS आदि का वर्णन करें
alfonx

1
यदि आपको stdout और stderr के बीच अंतर करने की आवश्यकता नहीं है, तो आप कथनों को जोड़ सकते हैं exec > >(tee ${LOG_FILE}) 2>&1
डार्कड्रैगन

5

मैं स्टैडआउट पर लॉग प्रदर्शित करना चाहता था और टाइमस्टैम्प के साथ लॉग फ़ाइल। उपरोक्त में से किसी भी उत्तर ने मेरे लिए काम नहीं किया। मैंने प्रक्रिया प्रतिस्थापन और निष्पादन कमांड का उपयोग किया और निम्नलिखित कोड के साथ आया। नमूना लॉग:

2017-06-21 11:16:41+05:30 Fetching information about files in the directory...

अपनी स्क्रिप्ट के शीर्ष पर निम्नलिखित पंक्तियाँ जोड़ें:

LOG_FILE=script.log
exec > >(while read -r line; do printf '%s %s\n' "$(date --rfc-3339=seconds)" "$line" | tee -a $LOG_FILE; done)
exec 2> >(while read -r line; do printf '%s %s\n' "$(date --rfc-3339=seconds)" "$line" | tee -a $LOG_FILE; done >&2)

आशा है कि यह किसी की मदद करता है!


क्या मेजबान निर्देशिका में प्रवेश करने के लिए सभी एप्लिकेशन त्रुटियों को लॉग करना संभव है ताकि यह devops में मदद करे ...
प्रसाद शिंदे

3

लॉग फ़ाइल के लिए आप पाठ डेटा में प्रवेश कर सकते हैं। निम्नलिखित कोड मदद कर सकता है

# declaring variables

Logfile="logfile.txt"   
MAIL_LOG="Message to print in log file"  
Location="were is u want to store log file"

cd $Location   
if [ -f $Logfile ]  
then   
echo "$MAIL_LOG " >> $Logfile

else        

touch $Logfile   
echo "$MAIL_LOG" >> $Logfile    

fi  

ouput: 2. लॉग फाइल पहले रन में बनाई जाएगी और अगले रन से अपडेट होती रहेगी। भविष्य के रन में गुम होने की स्थिति में, स्क्रिप्ट नई लॉग फ़ाइल बनाएगी।


1

मुझे वांछित आउटपुट प्राप्त करने का एक तरीका मिल गया है। हालांकि यह कुछ अपरंपरागत तरीका हो सकता है। वैसे भी यहाँ जाता है। Redir.env फ़ाइल में मेरे पास निम्नलिखित कोड हैं:

#####redir.env#####    
export LOG_FILE=log.txt

      exec 2>>${LOG_FILE}

    function log {
     echo "$1">>${LOG_FILE}
    }

    function message {
     echo "$1"
     echo "$1">>${LOG_FILE}
    }

फिर वास्तविक स्क्रिप्ट में मेरे पास निम्नलिखित कोड हैं:

#!/bin/sh 
. redir.env
echo "Echoed to console only"
log "Written to log file only"
message "To console and log"
echo "This is stderr. Written to log file only" 1>&2

यहाँ इको आउटपुट केवल कंसोल, लॉग आउटपुट को केवल लॉग फाइल और मैसेज आउटपुट दोनों लॉग फाइल और कंसोल में देता है।

उपरोक्त स्क्रिप्ट फ़ाइल को निष्पादित करने के बाद मेरे पास निम्न आउटपुट हैं:

सांत्वना में

कंसोल में
गूँजती केवल सांत्वना देने
को सांत्वना और प्रवेश करने के लिए

लॉग फ़ाइल के लिए

लॉग फ़ाइल में लॉग फ़ाइल में लिखा केवल
यह stderr है। केवल लॉग इन करने के लिए लिखित फ़ाइल
कंसोल और लॉग इन करने के लिए

उममीद है कि इससे मदद मिलेगी।


1

यह कोशिश करो, यह काम करेगा:

log_file=$curr_dir/log_file.txt
exec > >(tee -a ${log_file} )
exec 2> >(tee -a ${log_file} >&2)

यह exec > >(tee -a ${log_file} )मेरी जरूरतों के लिए एकदम सही काम करता है। ऊपर दिए गए पिछले समाधान मेरी स्क्रिप्ट के कुछ हिस्सों को बाधित कर देंगे जो यदि वे विफल हो गए तो बाहर निकल जाते हैं। धन्यवाद
मिशेल

1
    #
    #------------------------------------------------------------------------------
    # echo pass params and print them to a log file and terminal
    # with timestamp and $host_name and $0 PID
    # usage:
    # doLog "INFO some info message"
    # doLog "DEBUG some debug message"
    # doLog "WARN some warning message"
    # doLog "ERROR some really ERROR message"
    # doLog "FATAL some really fatal message"
    #------------------------------------------------------------------------------
    doLog(){
        type_of_msg=$(echo $*|cut -d" " -f1)
        msg=$(echo "$*"|cut -d" " -f2-)
        [[ $type_of_msg == DEBUG ]] && [[ $do_print_debug_msgs -ne 1 ]] && return
        [[ $type_of_msg == INFO ]] && type_of_msg="INFO " # one space for aligning
        [[ $type_of_msg == WARN ]] && type_of_msg="WARN " # as well

        # print to the terminal if we have one
        test -t 1 && echo " [$type_of_msg] `date "+%Y.%m.%d-%H:%M:%S %Z"` [$run_unit][@$host_name] [$$] ""$msg"

        # define default log file none specified in cnf file
        test -z $log_file && \
            mkdir -p $product_instance_dir/dat/log/bash && \
                log_file="$product_instance_dir/dat/log/bash/$run_unit.`date "+%Y%m"`.log"
        echo " [$type_of_msg] `date "+%Y.%m.%d-%H:%M:%S %Z"` [$run_unit][@$host_name] [$$] ""$msg" >> $log_file
    }
    #eof func doLog

0

मुझे यह बहुत उपयोगी लगता है कि एक लॉग फ़ाइल में stdout और stderr दोनों को जोड़ दिया जाए। मुझे अल्फोंक्स द्वारा एक समाधान देखकर खुशी हुई exec > >(tee -a), क्योंकि मैं सोच रहा था कि इसका उपयोग कैसे पूरा किया जाए exec। मैं यहाँ एक रचनात्मक समाधान का उपयोग करके आया था-डॉक्टर वाक्यविन्यास और .: /unix/80707/how-to-output-text-to-both-screen-and-file-inside-a-shell -script

मुझे पता चला कि zsh में, यहाँ "dios" निर्माण का उपयोग करके आउटपुट को कॉपी करने के लिए stdout / stderr और लॉग फ़ाइल दोनों में संशोधित किया जा सकता है:

#!/bin/zsh
LOG=$0.log
# 8 is an arbitrary number;
# multiple redirects for the same file descriptor 
# triggers "multios"
. 8<<\EOF /dev/fd/8 2>&2 >&1 2>>$LOG >>$LOG
# some commands
date >&2
set -x
echo hi
echo bye
EOF
echo not logged

यह execसमाधान के रूप में पढ़ने योग्य नहीं है, लेकिन इसका लाभ यह है कि आप स्क्रिप्ट के सिर्फ एक हिस्से को लॉग इन कर सकते हैं। बेशक, यदि आप ईओएफ को छोड़ देते हैं तो पूरी स्क्रिप्ट को लॉगिंग के साथ निष्पादित किया जाता है। मुझे यकीन नहीं है कि zshमल्टीओस कैसे लागू होता है, लेकिन इसकी तुलना में कम ओवरहेड हो सकता है tee। दुर्भाग्य से ऐसा लगता है कि कोई मल्टीओस का उपयोग नहीं कर सकता है exec

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