Ich habe mich gerade etwas mit langlaufenden Jobs (genauer: Backups, dazu soll es noch einen gesonderten Artikel geben) beschäftigt und wollte die etwas aufhübschen.
Timestamps in Ausgabe ergänzen
Als erstes habe ich nach etwas gesucht, was die Standardausgabe eines anderen Programmes mit Zeitstempeln versieht, damit ich grob zugucken kann, ob der Job noch lebt und wie schnell es vorangeht. Da ich auf die Schnelle nichts gefunden habe**, habe ich an ein kleines Shellskript gedacht: STDIN per Schleife lesen und jeweils den aktuellen Zeitstempel plus die gelesene Zeile ausgeben. Bei Zeitstempel dachte ich natürlich sofort an
date(1)
, aber pro Zeile einen externen Prozess aufzurufen… kann man machen, will man aber nicht. Also mal bei
printf(1)
gestöbert – das kann aber keine Zeitstempel. Zumindest das externe
printf
nicht – das eingebaute bash-printf kann sowas (also
help printf
statt
man printf
lesen).
Ergebnis ist sowas hier:
- langlaufender_Prozess | while read I; do printf '[%(%H:%M)T] '; echo "$I"; done
Soweit prima!
Exitcode vorne aus der Pipe
Nächste Herausforderung: Ich hätte gerne den Exitcode des langlaufenden Prozesses.
$?
funktioniert in dem Fall nicht mehr, das liefert den Returncode der while-Schleife. Also mal gegoogelt und, natürlich, Treffer auf
Stackoverflow. Bash löst das sehr elegent mit dem eingebauten Array
$PIPESTATUS
, das für jeden Teil der letzten Pipe den Returncode einzeln liefert.
Also sieht das Skript jetzt (vereinfacht) so aus:
- langlaufender_Prozess | while read I; do printf '[%(%H:%M)T] '; echo "$I"; done
- case ${PIPESTATUS[0]} in
- 0)
- echo rc=0, all ok
- ;;
-
- *)
- echo ERROR, STOPPING NOW
- exit 1
- ;;
- esac
Laufzeit messen
Zuguterletzt wollte ich noch eine Anzeige der Gesamtlaufzeit:
Teil 1 war „Sekunden zählen“. Hier war mein erster Gedanke auch wieder ein
date
-Aufruf, um mir die Sekunden nach Unix-Epoch geben zu lassen (Standard-Timestamp). Das einmal vor und einmal nach dem zu zählenden Teil, Differenz bilden, fertig ist die Laufzeit in Sekunden. Ich hätte erwartet, dass die Bash einen Unix-Timestamp liefern kann (um ihn z.B. an das
printf %()T
-Konstrukt zu verfüttern), aber das scheint nicht drin zu sein. Was die Bash aber hat und was auch vollkommen ausreicht, ist die Variable
$SECONDS
:
Each time this parameter is referenced, the number of seconds since shell invocation is returned. If a value is assigned to SECONDS, the value returned upon subsequent references is the number of seconds since the assignment plus the value assigned. If SECONDS is unset, it loses its special properties, even if it is subsequently reset.
Das lässt sich dann total einfach nutzen:
- SECONDS=0
- zu_benchmarkender_Teil
- echo $SECONDS Laufzeit
Zeitdauer formatieren
Teil 2 ist „hübsch machen“. Ich habe eine Anzahl von Sekunden. Wenn diese Dauer als Timestamp interpretiert wird, bedeutet sie „Sekunden nach Unix-Epoch“, wenn ich das nur als Stunden/Minuten/Sekunde ausgebe, habe ich exakt das, was ich brauche: aus 135 Sekunden wird „00:02:15“. Statt
date
geht das natürlich auch wieder über das eingebaute
printf
. Erst hatte ich immer eine Stunde zu viel im Ergebnis und mich schon gewundert, ob die Epoche nicht auf Mitternacht liegt, aber dann war es klar: Hier ist aktuell Winterzeit, also GMT+1. Das muss also noch rausgerechnet werden. Und bei Dauern kleiner einer Stunde kann man sich die Stundenanzeige kneifen, für Minuten das gleiche. Hübsch und fertig ist es also so geworden:
- SECONDS=0
- zu_benchmarkender_Teil
- DURATION=$(TZ=GMT printf '%(%Hh %Mm %Ss)T' $SECONDS)
- DURATION=${DURATION/00h }
- DURATION=${DURATION/00m }
- echo "Dauer: $DURATION"
Da kommt dann je nach Eingabe „35s“, „05m 30s“ oder „01h 00m 00s“ raus.
** Ich habe per
apropos
auf meinem System nach „timestamp“ gesucht. Da das nur mein Desktop war, kam nichts sinnvolles dabei heraus, was mich schon verwundert hat. Beim Schreiben dieser Zeilen habe ich das natürlich nochmal probiert, diesmal auf meinem Server und siehe da:
ts (1) - timestamp input
. Sowas war ja zu erwarten. In Debian kommt das aus dem Paket
moreutils. Egal – mit dem kurzen Stück Shell muss ich auf anderen Rechnern nicht noch neue Pakete installieren.
Mitch's Manga Blog am : Bunter Code
Mitch’s Manga Blog am : Nach dem Redesign: Doofe Dinge