web-dev-qa-db-fra.com

Écriture des sorties dans le fichier journal et la console

Dans Unix Shell, j’ai un fichier env (le fichier env définit les paramètres requis pour exécuter le script utilisateur, comme le nom et le chemin du fichier journal, les sorties de redirection et les erreurs dans le fichier journal, les détails de connexion à la base de données, etc.) qui redirige toutes les sorties (messages d'écho) et les erreurs dans le fichier journal à partir du script exécuté à l'aide du code suivant:

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

Le fichier env est exécuté au début de chaque script. En raison du code ci-dessus dans le fichier env, toutes les sorties de la console pouvant être des sorties utilisateur ou des erreurs sont directement sorties dans le fichier journal, ce dont j'avais réellement besoin.

Mais il y a des sorties utilisateur sélectives que je souhaite voir affichées à la fois dans la console et dans le fichier journal. Mais à cause du code ci-dessus, je ne peux pas le faire.

Je sais que si je supprime le code ci-dessus, je peux obtenir le résultat souhaité pour ce cas, mais je devrai écrire manuellement toutes les autres sorties dans le fichier journal, ce qui n'est pas une tâche facile.

Existe-t-il un moyen d’obtenir la sortie à la fois dans la console et dans le fichier journal sans supprimer les codes ci-dessus?

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

enverrait les sorties stdout et stderr dans le fichier journal, mais vous laisserait aussi le disque 3 connecté à la console, ce qui vous permettrait de

echo "Some console message" 1>&3

écrire un message uniquement sur la console, ou

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

écrire un message dans les deux la console et le fichier journal - tee envoie sa sortie à son propre fd 1 (qui est ici le LOG_FILE) et au fichier que vous lui avez demandé d'écrire (qui est ici est fd 3, c’est-à-dire la console).

Exemple:

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

serait imprimer

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

sur la console et mettre

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

dans le fichier journal.

79
Ian Roberts

Oui, vous voulez utiliser tee:

tee - lit à partir de l'entrée standard et écrit dans la sortie standard et les fichiers

Il suffit de diriger votre commande vers tee et de passer le fichier en argument, comme suit:

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

Cela permet d’imprimer la sortie sur STDOUT et d’écrire la même sortie dans un fichier journal. Voir man tee pour plus d'informations.

Notez que stderr ne sera pas écrit dans le fichier journal. Par conséquent, si vous souhaitez combiner les deux flux, utilisez:

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

J'ai essayé la réponse de Joonty, mais j'ai aussi eu 

exec non trouvé

erreur. C’est ce qui me convient le mieux ( confirmé travailler aussi en zsh):

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

Le fichier /tmp/both.log contient ensuite

this is stdout
chmmm command not found 

Le fichier /tmp/both.log est ajouté à moins que vous ne retiriez le -a de tee.

Astuce: >(...) est une substitution de processus. Il laisse la exec à la commande tee comme s'il s'agissait d'un fichier.

27
alfonx

pour le fichier journal, vous pouvez dater les données textuelles. le code suivant peut aider

# 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. Le fichier journal sera créé lors de la première exécution et continuera à se mettre à jour lors des exécutions suivantes. Si le fichier journal est manquant lors d'une prochaine exécution, le script créera un nouveau fichier journal.

3
user2197712

Je voulais afficher les journaux sur stdout et le fichier journal avec l'horodatage. Aucune des réponses ci-dessus n'a fonctionné pour moi. Je me suis servi de process substitution et exec command pour créer le code suivant . Des exemples de journaux: 

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

Ajoutez les lignes suivantes en haut de votre script: 

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)

J'espère que cela aide quelqu'un!

3
Jyoti Dhiman

J'ai trouvé un moyen d'obtenir le résultat souhaité. Bien que cela puisse être un peu peu orthodoxe. En tout cas ici ça va. Dans le fichier redir.env, j'ai le code suivant:

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

Ensuite, dans le script actuel, j'ai les codes suivants:

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

Ici, echo affiche uniquement les informations sur la console, log fournit uniquement le fichier journal et message le fichier journal et la console.

Après avoir exécuté le fichier de script ci-dessus, j'ai les résultats suivants:

En console

En console
Echo à la console seulement
Console et log

Pour le fichier journal

Dans le fichier journal Écrit dans le fichier journal uniquement
C'est stderr. Écrit dans le fichier journal uniquement
Console et log

J'espère que cette aide.

1
abinash shrestha
    #
    #------------------------------------------------------------------------------
    # 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

Je trouve très utile d’ajouter stdout et stderr à un fichier journal. J'étais heureux de voir une solution de alfonx avec exec > >(tee -a), car je me demandais comment accomplir cela avec exec. Je suis tombé sur une solution créative utilisant la syntaxe here-doc et .: https://unix.stackexchange.com/questions/80707/how-to-output-text-to-both-screen-and-file-inside- a-shell-script

J'ai découvert qu'en zsh, la solution here-doc peut être modifiée à l'aide de la construction "multios" afin de copier le résultat dans stdout/stderr et le fichier journal:

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

Elle n’est pas aussi lisible que la solution exec mais elle a l’avantage de vous permettre de ne consigner qu’une partie du script. Bien sûr, si vous omettez le EOF, alors tout le script est exécuté avec la journalisation. Je ne suis pas sûr de savoir comment zsh implémente les multios, mais il peut y avoir moins de temps système que tee. Malheureusement, il semble que l'on ne puisse pas utiliser le multios avec exec.

0
Metamorphic

Essayez ceci, cela fera le travail:

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