Mettez un texte devant chaque nouvelle ligne qu'un programme imprime sur stdout

9

Je veux donc faire un peu de journalisation et pour cela, je veux mettre une date devant la sortie d'un script bash. Le problème est qu'il a plusieurs lignes de sortie. Je peux seulement mettre la date avant la sortie entière. Mais alors j'ai une ligne sans date dans les journaux. Bien sûr, je peux supposer que la date de la ligne ci-dessus est la même, mais j'espérais qu'il existe une solution. Merci d'avance!

Voici mon script qui appelle un autre script:

#!/bin/sh
echo $(date "+%F %T") : starting script
echo $(date "+%F %T") : $(./script.sh)
echo $(date "+%F %T") :script ended

Voici la sortie:

2012-07-26 15:34:12 : starting script
2012-07-26 15:35:14 : First line of output
second line of output
2012-07-26 15:35:17 : script ended

Et c'est ce que j'aimerais avoir:

2012-07-26 15:34:12 : starting script
2012-07-26 15:35:14 : First line of output
2012-07-26 15:35:15 : second line of output
2012-07-26 15:35:17 : script ended
tzippy
la source
Je ne suppose pas que vous puissiez simplement changer le deuxième script?
jmetz
Non, malheureusement non. Voilà pourquoi je suis venu ici.
tzippy

Réponses:

9

Selon une question similaire sur Stack Overflow , il existe 2 excellentes options.

awk ( réponse )

<command> | awk '{ print strftime("%Y-%m-%d %H:%M:%S"), $0; }'

annoter ( réponse )

annotate est un petit script bash, qui peut être obtenu directement via le lien fourni ici, ou, sur les systèmes basés sur Debian, via le package devscripts(sous la forme de annotate-output).

Oliver Salzburg
la source
3

Je pense que vous pouvez utiliser awk pour cela:

./script.sh | awk '{ print strftime()" : "$0; }'

(voir http://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html pour mettre en forme la date renvoyée par strftime ())

Flinth
la source
2
awk: calling undefined function strftime- est-ce spécifique à gawk?
Daniel Beck
Maintenant que vous le mentionnez, oui, il semble que ce soit: /
Flinth le
2

Vous pouvez utiliser awk

./script.sh | awk '{ print d,$1}' "d=$(date "+%F %T")"

awkprend un flux d'entrée et modifie sa sortie. Ce script indique "imprimer d suivi de la sortie d'origine", puis remplit davec la date.

Paul
la source
1
Cela n'évalue-t-il pas l' dateexpression une seule fois également, de sorte que toutes ces lignes s'impriment en même temps?
Daniel Beck
@DanielBeck Oui, c'est vrai - j'avais supposé que c'était la date à chaque fois, mais je venais de terminer mon test assez rapidement
Paul
1

Cela imprimera la date et l'heure actuelles avant chaque ligne de sortie de ./script.sh:

set -f
./script.sh | while read -r LINE; do echo $(date "+%F %T") : "$LINE"; done
set +f

Comment ça fonctionne

  • set -fdésactive l'expansion bash (ou echo *n'imprime pas un véritable astérisque).

  • while read -r LINE; do ... doneenregistre une ligne de sortie dans la variable $LINEet s'exécute ...jusqu'à ce que toutes les lignes soient traitées.

  • echo $ (date "+% F% T"): "$ LINE" imprime la ligne avec l'heure et la date actuelles.

  • set +f active l'expansion bash, de sorte qu'elle n'interfère pas avec le reste de votre script bash.

Dennis
la source
Il n'est évalué qu'une seule fois, donc chaque sedinsère la même date, juste avant de démarrer le deuxième script. Probablement pas ce que l'utilisateur veut ...
Daniel Beck
Je ne pense pas que cette tentative fonctionnera non plus. AFAIK, le sous-shell entier est évalué complètement en premier, puis la boucle est parcourue. Alors maintenant, les temps sont postérieurs à l'exécution.
Daniel Beck
Votre exemple ne fonctionne pas, car vous retardez uniquement la sortie, pas l'exécution de ls. Essayez simplement votre script avec ce qui suit script.sh: #!/bin/bash(nouvelle ligne)echo 1 ; sleep 1 ; echo 2 ; sleep 2 ; echo 3 ; sleep 3 ; echo 4
Daniel Beck
À utiliser readavec une whileboucle au lieu d'une boucle for.
chepner
@chepner: Bonne idée.
Dennis