Stellen Sie vor jede neue Zeile, die ein Programm auf stdout druckt, einen Text

9

Ich möchte also ein wenig protokollieren und dafür ein Datum vor die Ausgabe eines Bash-Skripts setzen. Das Problem ist, dass es mehrere Ausgabezeilen gibt. Ich kann nur das Datum vor die gesamte Ausgabe setzen. Aber dann habe ich eine Zeile ohne Datum in den Protokollen. Natürlich kann ich davon ausgehen, dass das Datum in der obigen Zeile das gleiche ist, aber ich hatte gehofft, dass es eine Lösung gibt. Danke im Voraus!

Dies ist mein Skript, das ein anderes Skript aufruft:

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

Dies ist die Ausgabe:

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

Und das hätte ich gerne:

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
quelle
Ich nehme nicht an, dass Sie einfach das zweite Skript ändern könnten?
Jmetz
Nein, leider nicht. Deshalb bin ich hergekommen.
Zippy

Antworten:

9

Laut einer ähnlichen Frage zu Stack Overflow gibt es zwei großartige Optionen.

awk ( Antwort )

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

kommentieren ( Antwort )

annotate ist ein kleines Bash-Skript, das entweder direkt über den hier angegebenen Link oder auf Debian-basierten Systemen über das Paket devscripts(in Form von annotate-output) abgerufen werden kann .

Oliver Salzburg
quelle
3

Ich denke, dass Sie awk dafür verwenden können:

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

( Informationen zum Formatieren des von strftime () zurückgegebenen Datums finden Sie unter http://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html. )

Flinth
quelle
2
awk: calling undefined function strftime- Ist das spezifisch für gawk?
Daniel Beck
Nun, da Sie es erwähnen, scheint es ja: /
Flinth
2

Sie können verwenden awk

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

awkNimmt einen Eingabestream und ändert seine Ausgabe. Dieses Skript sagt "print d gefolgt von der Originalausgabe" und füllt dann dmit dem Datum.

Paul
quelle
1
Wertet dies den dateAusdruck nicht auch nur einmal aus, so dass alle diese Zeilen zur gleichen Zeit gedruckt werden?
Daniel Beck
@DanielBeck Ja, das stimmt - ich hatte angenommen, dass es jedes Mal das Datum aufnimmt, aber meinen Test gerade schnell genug beendet
Paul
1

Dies wird das aktuelle Datum und die aktuelle Uhrzeit vor jeder Ausgabezeile von ./script.sh:

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

Wie es funktioniert

  • set -fDeaktiviert die Bash-Erweiterung (oder echo *druckt keinen Stern).

  • while read -r LINE; do ... doneSpeichert eine Ausgabezeile in der Variablen $LINEund wird ausgeführt ..., bis alle Zeilen verarbeitet wurden.

  • echo $ (Datum "+% F% T"): "$ LINE" druckt die Zeile mit der aktuellen Uhrzeit und dem aktuellen Datum.

  • set +f Schaltet die Bash-Erweiterung wieder ein, damit der Rest Ihres Bash-Skripts nicht beeinträchtigt wird.

Dennis
quelle
Es wird nur einmal ausgewertet, daher sedfügt jeder das gleiche Datum ein, unmittelbar bevor das zweite Skript gestartet wird. Wahrscheinlich nicht das, was der Benutzer will ...
Daniel Beck
Ich denke nicht, dass dieser Versuch auch funktionieren wird. AFAIK, die ganze Subshell wird zuerst komplett ausgewertet, dann wird die Schleife durchlaufen. Also jetzt sind die Zeiten von nach der Hinrichtung.
Daniel Beck
Ihr Beispiel funktioniert nicht, da Sie nur die Ausgabe verzögern, nicht die Ausführung von ls. Probieren Sie Ihr Skript einfach mit folgendem Code aus script.sh: #!/bin/bash(newline)echo 1 ; sleep 1 ; echo 2 ; sleep 2 ; echo 3 ; sleep 3 ; echo 4
Daniel Beck
Verwenden Sie readmit einer whileSchleife anstelle einer for-Schleife.
Chepner
@chepner: Gute Idee.
Dennis