it-swarm.com.de

Ausgaben in Protokolldatei und Konsole schreiben

In der Unix-Shell habe ich eine env-Datei ( env-Datei definiert die Parameter, die zum Ausführen des Benutzerskripts erforderlich sind, z. B. Name und Pfad der Protokolldatei, Umleiten von Ausgaben und Fehlern in Protokolldateien, Datenbankverbindungsdetails usw. ), die alle umleiten gibt ( echo messages ) und Fehler aus dem ausgeführten Skript in die Protokolldatei mit folgendem Code aus:

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

Die env-Datei wird am Anfang jedes Skripts ausgeführt. Aufgrund des obigen Codes in der env-Datei werden alle Konsolenausgaben, bei denen es sich möglicherweise um Benutzerausgaben oder Fehler handelt, direkt in die Protokolldatei ausgegeben. Dies ist, was ich eigentlich brauchte.

Es gibt jedoch einige selektive Benutzerausgaben, die sowohl in der Konsole als auch in der Protokolldatei angezeigt werden sollen. Aber aufgrund des obigen Codes kann ich das nicht.

Ich weiß, dass ich, wenn ich den obigen Code entferne, das gewünschte Ergebnis für diesen Fall erhalten kann, aber ich muss alle anderen Ausgaben manuell in die Protokolldatei schreiben, was keine einfache Aufgabe ist.

Gibt es eine Möglichkeit, die Ausgabe in der Konsole und in der Protokolldatei abzurufen, ohne die obigen Codes zu entfernen?

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

würde die Ausgabe von stdout und stderr in die Protokolldatei senden, aber Sie würden auch Fd 3 mit der Konsole verbunden lassen, so dass Sie dies tun können

echo "Some console message" 1>&3

um eine Nachricht nur an die Konsole zu schreiben, oder

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

um eine Nachricht an beide die Konsole und die Protokolldatei zu schreiben - tee sendet seine Ausgabe sowohl an die eigene Fd 1 (hier der LOG_FILE) als auch an die Datei, in die Sie sie schreiben (die hier angegeben wird) ist fd 3, dh die Konsole).

Beispiel:

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

würde drucken

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

auf der Konsole und setzen

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

in die Protokolldatei.

79
Ian Roberts

Ja, Sie möchten tee verwenden:

tee - Lesen von Standardeingaben und Schreiben in Standardausgabe und Dateien

Pfeifen Sie einfach Ihren Befehl zum Abschlag und übergeben Sie die Datei als Argument wie folgt:

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

Dies gibt die Ausgabe an STDOUT aus und schreibt dieselbe Ausgabe in eine Protokolldatei. Weitere Informationen finden Sie unter man tee.

Beachten Sie, dass dies nicht stderr in die Protokolldatei schreibt. Wenn Sie also die beiden Streams kombinieren möchten, verwenden Sie Folgendes:

exec 1 2>&1 | tee ${LOG_FILE}
33
Jon Cairns

Ich habe Joontys Antwort ausprobiert, aber ich habe auch die 

exec: 1: nicht gefunden

error. Dies funktioniert am besten für mich ( bestätigt auch in zsh zu arbeiten):

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

Die Datei /tmp/both.log enthält danach

this is stdout
chmmm command not found 

Das /tmp/both.log wird angehängt, es sei denn, Sie entfernen -a vom Abschlag.

Hinweis: >(...) ist eine Prozessersetzung. Es lässt die exec zum tee-Befehl, als wäre es eine Datei.

27
alfonx

für die Protokolldatei können Sie ein Datum eingeben, um Textdaten einzugeben. Folgender Code kann helfen

# 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  

ausgabe: 2. Die Protokolldatei wird beim ersten Durchlauf erstellt und beim nächsten Durchlauf aktualisiert. Falls die Protokolldatei bei der zukünftigen Ausführung nicht vorhanden ist, erstellt das Skript eine neue Protokolldatei.

3
user2197712

Ich wollte Protokolle zusammen mit dem Zeitstempel auf stdout und log file anzeigen. Keine der obigen Antworten funktionierte für mich. Ich habe den Befehl process substitution und exec verwendet und den folgenden Code gefunden Beispielprotokolle: 

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

Fügen Sie am Anfang Ihres Skripts folgende Zeilen ein: 

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)

Hoffe das hilft jemandem!

3
Jyoti Dhiman

Ich habe einen Weg gefunden, um die gewünschte Ausgabe zu erhalten. Obwohl es etwas unorthodox sein kann. Sowieso geht es hier. In der Datei redir.env habe ich folgenden Code:

#####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}
    }

Dann habe ich im eigentlichen Skript folgende Codes:

#!/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

Hier gibt echo nur die Konsole aus, log nur die Protokolldatei und Nachricht die Protokolldatei und die Konsole.

Nach dem Ausführen der obigen Skriptdatei habe ich folgende Ausgaben:

In der Konsole

In Konsole
Nur an die Konsole gesendet
Um zu trösten und zu protokollieren

Für die Protokolldatei

In Protokolldatei Nur in die Protokolldatei geschrieben
Das ist stderr. Nur in die Protokolldatei geschrieben
Um zu trösten und zu protokollieren

Ich hoffe das hilft.

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
1
Yordan Georgiev

Ich finde es sehr nützlich, stdout und stderr an eine Protokolldatei anzuhängen. Ich war froh, eine Lösung von alfonx mit exec > >(tee -a) zu sehen, weil ich mich fragte, wie ich dies mit exec erreichen kann. Ich bin auf eine kreative Lösung gestoßen, die hier-doc-Syntax und .: https://unix.stackexchange.com/questions/80707/how-to-output-text-to-both-screen-und-file-inside- verwendet. a-Shell-Skript

Ich habe festgestellt, dass die Here-Doc-Lösung in zsh mit dem "Multios" -Konstrukt modifiziert werden kann, um die Ausgabe in sowohl stdout/stderr als auch in die Protokolldatei zu kopieren:

#!/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

Es ist nicht so lesbar wie die exec-Lösung, hat aber den Vorteil, dass Sie nur einen Teil des Skripts protokollieren können. Wenn Sie EOF weglassen, wird das gesamte Skript natürlich mit Protokollierung ausgeführt. Ich bin nicht sicher, wie zsh Multios implementiert, es kann jedoch weniger Aufwand als tee geben. Leider scheint es, dass man mit exec keine Multios verwenden kann.

0
Metamorphic

Probieren Sie es aus, es erledigt die Arbeit:

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