Comment puis-je obtenir à la fois STDOUT et STDERR pour accéder au terminal et un fichier journal?

J’ai un script qui sera exécuté de manière interactive par des utilisateurs non techniques. Le script écrit les mises à jour de statut sur STDOUT afin que l’utilisateur puisse être sûr que le script fonctionne correctement.

Je souhaite que les deux fichiers STDOUT et STDERR soient redirigés vers le terminal (afin que l’utilisateur puisse voir que le script fonctionne aussi bien qu’il ya un problème). Je souhaite également que les deux stream soient redirigés vers un fichier journal.

J’ai vu un tas de solutions sur le net. Certains ne fonctionnent pas et d’autres sont horriblement compliqués. J’ai développé une solution réalisable (que je vais entrer en tant que réponse), mais c’est très compliqué.

La solution idéale serait une ligne de code unique qui pourrait être intégrée au début de tout script qui envoie les deux stream au terminal et à un fichier journal.

EDIT: redirect STDERR vers STDOUT et redirect le résultat vers les travaux de départ, mais cela dépend des utilisateurs qui se souviennent de redirect et de diriger la sortie. Je veux que la journalisation soit infaillible et automatique (c’est pourquoi je voudrais pouvoir intégrer la solution dans le script lui-même).

Utilisez “tee” pour redirect vers un fichier et l’écran. Selon le shell que vous utilisez, vous devez d’abord redirect stderr en stdout en utilisant

./a.out 2>&1 | tee output 

ou

 ./a.out |& tee output 

Dans csh, il y a une commande intégrée appelée “script” qui capture tout ce qui va à l’écran dans un fichier. Vous le lancez en tapant “script”, puis en faisant tout ce que vous voulez capturer, puis appuyez sur control-D pour fermer le fichier de script. Je ne connais pas d’équivalent pour sh / bash / ksh.

De plus, comme vous avez indiqué que vous pouvez modifier vos scripts sh, vous pouvez effectuer la redirection en interne en entourant tout le script par des accolades ou des crochets, comme

  #!/bin/sh { ... whatever you had in your script before } 2>&1 | tee output.file 

Approchant une demi-décennie plus tard …

Je crois que c’est la “solution parfaite” recherchée par le PO.

Voici une ligne que vous pouvez append en haut de votre script Bash:

 exec > >(tee -a $HOME/logfile) 2>&1 

Voici un petit script démontrant son utilisation:

 #!/usr/bin/env bash exec > >(tee -a $HOME/logfile) 2>&1 # Test redirection of STDOUT echo test_stdout # Test redirection of STDERR ls test_stderr___this_file_does_not_exist 

(Remarque: Cela ne fonctionne qu’avec Bash. Cela ne fonctionnera pas avec / bin / sh.)

Adapté d’ ici l’original n’a pas, d’après ce que je peux dire, attraper STDERR dans le fichier journal. Corrigé avec une note d’ ici .

pour redirect stderr vers stdout, ajoutez ceci à votre commande: 2>&1 Pour sortir vers le terminal et vous connecter au fichier, vous devez utiliser tee

Les deux ensemble ressembleraient à ceci:

  mycommand 2>&1 | tee mylogfile.log 

EDIT: Pour intégrer dans votre script, vous feriez la même chose. Donc votre script

 #!/bin/sh whatever1 whatever2 ... whatever3 

finirait comme

 #!/bin/sh ( whatever1 whatever2 ... whatever3 ) 2>&1 | tee mylogfile.log 

Utilisez le programme de départ et emstackz stderr sur stdout.

  program 2>&1 | tee > logfile 

J’ai créé un script appelé “RunScript.sh”. Le contenu de ce script est:

 ${APP_HOME}/${1}.sh ${2} ${3} ${4} ${5} ${6} 2>&1 | tee -a ${APP_HOME}/${1}.log 

Je l’appelle comme ceci:

 ./RunScript.sh ScriptToRun Param1 Param2 Param3 ... 

Cela fonctionne, mais il faut que les scripts de l’application soient exécutés via un script externe. C’est un peu maladroit.

Un an plus tard, voici un vieux script bash pour enregistrer quoi que ce soit. Par exemple,
teelog make ... connecte à un nom de journal généré (et voit aussi le truc pour enregistrer les marques nestedes).

 #!/bin/bash me=teelog Version="2008-10-9 oct denis-bz" Help() { cat <&1 | tee `day`-command-args.log That is, stdout and stderr go to both the screen, and to a log file. (The Unix "tee" command is named after "T" pipe fittings, 1 in -> 2 out; see http://en.wikipedia.org/wiki/Tee_(command) ). The default log file name is made up from "command" and all the "args": $me cmd -opt dir/file logs to `day`-cmd--opt-file.log . To log to xx.log instead, either export log=xx.log or $me log=xx.log cmd ... If "logdir" is set, logs are put in that directory, which must exist. An old xx.log is moved to /tmp/\$USER-xx.log . The log file has a header like # from: command args ... # run: date pwd etc. to show what was run; see "From" in this file. Called as "Log" (ln -s $me Log), Log anycommand ... logs to a file: command args ... > `day`-command-args.log and tees stderr to both the log file and the terminal -- bash only. Some commands that prompt for input from the console, such as a password, don't prompt if they "| tee"; you can only type ahead, carefully. To log all "make" s, including nested ones like cd dir1; \$(MAKE) cd dir2; \$(MAKE) ... export MAKE="$me make" ! # See also: output logging in screen(1). exit 1 } #------------------------------------------------------------------------------- # bzutil.sh denisbz may2008 -- day() { # 30mar, 3mar /bin/date +%e%h | tr '[AZ]' '[az]' | tr -d ' ' } edate() { # 19 May 2008 15:56 echo `/bin/date "+%e %h %Y %H:%M"` } From() { # header # from: $* # run: date pwd ... case `uname` in Darwin ) mac=" mac `sw_vers -productVersion`" esac cut -c -200 <= 100 )) && break # max len 100 done # no blanks etc in logfilename please, tr them to "-" echo $logdir/` echo "$log".log | tr -C '.:+=[:alnum:]_\n' - ` } #------------------------------------------------------------------------------- case "$1" in -v* | --v* ) echo "$0 version: $Version" exit 1 ;; "" | -* ) Help esac # scan log= etc -- while [[ $1 == [a-zA-Z_]*=* ]]; do export "$1" shift done : ${logdir=.} [[ -w $logdir ]] || { echo >&2 "error: $me: can't write in logdir $logdir" exit 1 } : ${log=` logfilename "$@" `} [[ -f $log ]] && /bin/mv "$log" "/tmp/$USER-${log##*/}" case ${0##*/} in # basename log | Log ) # both to log, stderr to caller's stderr too -- { From "$@" "$@" } > $log 2> >(tee /dev/stderr) # bash only # see http://wooledge.org:8000/BashFAQ 47, stderr to a pipe ;; * ) #------------------------------------------------------------------------------- { From "$@" # header: from ... date pwd etc. "$@" 2>&1 # run the cmd with stderr and stdout both to the log } | tee $log # mac tee buffers stdout ? esac 

Utilisez la commande de script dans votre script (script man 1)

Créez un script shell (2 lignes) qui configure le script (), puis appelle exit.

Partie 1: wrap.sh

 #!/bin/sh script -c './realscript.sh' exit 

Partie 2: realscript.sh

 #!/bin/sh echo 'Output' 

Résultat:

 ~: sh wrap.sh Script started, file is typescript Output Script done, file is typescript ~: cat typescript Script started on fr. 12. des. 2008 kl. 18.07 +0100 Output Script done on fr. 12. des. 2008 kl. 18.07 +0100 ~: