243 votes

Rediriger les copie de stdout vers fichier journal dans bash script lui-même

Je sais comment faire pour rediriger stdout vers un fichier :

Cela mettra le « test » dans le fichier foo.log.

Maintenant je veux rediriger la sortie dans le journal fichier et gardez-le sur stdout

par exemple il peut être fait trivialement de dehors le script :

mais j’ai envie de le faire depuis l’intérieur

J'ai essayé

mais il n’a pas fonctionné

307voto

DevSolar Points 18897
<pre><code></code><p><code></code><code></code><code></code><code></code>.</p></pre>

180voto

Adam Spiers Points 4193

La accepté de réponse ne permet pas de conserver STDERR dans un fichier séparé descripteur. Cela signifie que

./script.sh >/dev/null

ne sera pas de sortie bar à la borne, uniquement pour les fichiers de log, et

./script.sh 2>/dev/null

sortie à la fois foo et bar à la borne. Clairement ce n'est pas le comportement d'un utilisateur normal est susceptible de s'attendre. Cela peut être fixe à l'aide de deux différents tee processus à la fois en ajoutant à la même fichier journal:

#!/bin/bash

exec >  >(tee -a foo.log)
exec 2> >(tee -a foo.log >&2)

echo "foo"
echo "bar" >&2

(À noter que ce qui précède n'est pas d'abord de tronquer le fichier journal - si vous voulez que le comportement que vous devez ajouter

>foo.log

en haut du script.)

La POSIX.1-2008 date de spécification d' tee(1) exige que la sortie est sans tampon, c'est à dire même pas en ligne de tampon, de sorte que dans ce cas, il est possible que STDOUT et STDERR pourrait se retrouver sur la même ligne d' foo.log; toutefois, cela pourrait également se produire sur le terminal, de sorte que le fichier journal sera un fidèle reflet de ce qui pourrait être vu sur le terminal, si ce n'est un miroir exact. Si vous voulez la sortie standard les lignes clairement séparées de la STDERR lignes, envisager d'utiliser deux fichiers journaux, éventuellement avec timbre à date des préfixes sur chaque ligne pour permettre chronologique remontage plus tard.

28voto

jbarlow Points 875

L'on a accepté la réponse est certainement le meilleur choix pour bash. Je travaille dans une Busybox environnement sans accès à bash, et il ne comprend pas l' exec > >(tee log.txt) de la syntaxe. Il également ne pas faire exec >$PIPE correctement, en essayant de créer un fichier avec le même nom que le canal nommé, qui ne parvient pas et se bloque.

J'espère que cela serait utile à quelqu'un d'autre qui n'ont pas de bash.

Aussi, pour toute personne utilisant un tube nommé, il est sûr d' rm $PIPE, parce que les délie le tuyau de la VFS, mais le processus qui l'utilisent encore de maintenir un compte de référence sur elle jusqu'à ce qu'ils sont finis.

Notez l'utilisation de $* n'est pas nécessairement sans danger.

#!/bin/sh

if [ "$SELF_LOGGING" != "1" ]
then
    PIPE=tmp.fifo
    mkfifo $PIPE

    # Keep PID of this process
    SELF_LOGGING=1 sh $0 $* >$PIPE &
    PID=$!

    tee logfile <$PIPE &

    # Safe to rm pipe because the child processes have references to it
    rm $PIPE    
    wait $PID

    # Return same error code as original process
    exit $?
fi

19voto

WReach Points 13161

À l’intérieur de votre fichier de script, mettre toutes les commandes entre parenthèses, comme ceci :

10voto

fgunger Points 81

À l'aide de la accepté de répondre à mon script ne cesse de revenir exceptionnellement précoce (à droite après 'exec > >(eto ...)') en laissant le reste de mon script qui s'exécute en arrière-plan. Comme je ne pouvais pas obtenir la solution à travailler mon chemin, j'ai trouvé une autre solution/contourner le problème:

# Logging setup
logfile=mylogfile
mkfifo ${logfile}.pipe
tee < ${logfile}.pipe $logfile &
exec &> ${logfile}.pipe
rm ${logfile}.pipe

# Rest of my script

Cela rend la sortie de script aller du processus, à travers le tuyau dans le sous-processus d'arrière-plan de 'tee' qui enregistre tout à disque et à l'original de la sortie standard du script.

Notez que 'exec &>' redirige les deux stdout et stderr, on pourrait rediriger séparément si l'on aime, ou "exec >" si nous voulons juste la sortie standard stdout.

Même tu le tuyau est supprimé du système de fichiers dans le début du script, il continuera à fonctionner jusqu'à ce que le processus se termine. Nous n'avons pas de référence en utilisant le nom du fichier après le rm-ligne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X