rediriger et consigner la sortie du script

8

J'essaie de ranger les extraits suivants, les objectifs de conception sont de consigner toutes les sorties d'un script et ne doivent pas être un wrapper. Moins de lignes, c'est mieux.

Je ne me soucie pas des entrées utilisateur (à ce stade), les scripts cibles sont exécutés de manière non interactive.

L'extrait doit

  • sortie stdout pour se connecter et toujours en écho sur la console
  • sortie stderr pour se connecter, et echo pour la console si le débogage est activé
  • les messages stderr doivent être préfixés avec des horodatages et autres utilités

Pour le moment, j'ai ce qui suit qui ne teste que sous les versions récentes de bash (4.2+?) Comme dans Ubuntu précis, mais se comporte mal sur CentOS6.

DEBUG_LOG="${0##*/}.log"

# copy stdout to log always and echo to console
exec >  >(tee -a ${DEBUG_LOG})           

# copy stderr to log only, unless debugging is enabled
[ $DEBUG_TEST = "true" ] \
  && exec 2> >(tee -a ${DEBUG_LOG} >&2) \
  || exec 2>> ${DEBUG_LOG}

Ensuite ceci...

# Expand escaped characters, wrap at 70 chars on spaces, 
# and indent wrapped lines
msg_log() { 
  echo -e "$(date +%T) ${0##*/}: $1" \
    | fold -w70 -s | sed '2~1s/^/  /' >&2; 
}
msg_con() { 
  if [ "${DEBUG_TEST}" = "true" ]; then 
    msg_log "$1"
  else
    echo -e "$1" | fold -w70 -s | sed '2~1s/^/  /'; 
  fi
}

Au lieu de echoje peux appeler une de ces procédures msg, par exemple msg_con "hello world".
De plus, la sortie du script ira ensuite à stderr en définissant une variable d'environnement au moment de l'appel, par exemple  DEBUG_TEST=true myscript.

J'ai lu que exec peut ne pas fonctionner dans certains shells tels que busybox. Il y a une combinaison mkfifo et fork sur https://stackoverflow.com/a/5200754 qui fait quelque chose de similaire mais je préfère ne pas utiliser de fork sauf si absolument nécessaire.

Préférez les exemples bash s'il vous plaît, mais quelque chose qui fonctionne sous sh ou qui est plus portable serait bien. Des idées?

Glenn
la source

Réponses:

1
function startLogging {
    exec > >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' | tee -a $logfile)
    [ ! -z "$DEBUG" ] && exec 2>&1 || exec 2> >(gawk -v pid=$$ '{ print strftime("%F-%T"),pid,$0; fflush(); }' >>$logfile)
    echo "=== Log started for $$ at $(date +%F-%T) ==="
}

Vous devez avoir $ logfile défini sur quelque chose

Angelo
la source
C'est plutôt cool, la façon dont je le lis, vous utilisez gawk pour ajouter les en-têtes de message. Cela aura pour effet secondaire supplémentaire de les ajouter également aux sorties de commande.
Glenn
La raison d'utiliser gawk pour ajouter un horodatage (et un identifiant de processus) à chaque ligne de journal est parce qu'elle sera exécutée à chaque écriture de la sortie et mettra donc à jour l'horodatage. Il est également important d'utiliser gawk et non awk car je pense que la fonction strftime est une extension GNU.
Angelo
0

exec > filenamedevrait fonctionner dans sh, et cela fonctionne en fait dans busybox v1.15.3 (novembre 2011). Mais la substitution de processus >(command)n'est pas transférable car c'est l'extension bash. Évitez simplement de l'utiliser dans des scripts. Pourquoi >>ne vous suffit-il pas?

exec 1>>${DEBUG_LOG}
exec 2>>${DEBUG_LOG}

Une autre solution consiste à spécifier la redirection en dehors de vos scripts. Lorsque votre script est invoqué en arrière-plan (par cron, ou script système, etc.), ils doivent être appelés comme ceci

./my_script 1>>${DEBUG_LOG} 2>>${DEBUG_LOG}

Lorsque vous appelez le script manuellement et que vous souhaitez voir la sortie, appelez-le simplement sans redirection.

Kirikaza
la source
1
Le demandeur de questions souhaite que la sortie du script soit envoyée à la fois à la console et au fichier journal.
0

Ces deux exemples feront ce que sont vos objectifs déclarés

echo -n $(date) >> $DEBUG_LOG
command 2>&1 | tee -a $DEBUG_LOG

ou

echo -n $(date) >> $DEBUG_LOG
command >> $DEBUG_LOG 2>&1
Luc
la source
0

Vous pouvez utiliser la teecommande ou les scriptdeux commandes sont vraiment utiles.

Falk
la source
le script a l'air cool, mais ne fait pas vraiment ce dont j'ai besoin, le comportement doit être modifiable pendant l'exécution.
Glenn