Skriptausgabe umleiten und protokollieren

8

Ich versuche, die folgenden Schnipsel aufzuräumen. Entwurfsziele sind die Protokollierung aller Ausgaben eines Skripts und sollten kein Wrapper sein. Weniger Zeilen sind besser.

Benutzereingaben interessieren mich nicht (zu diesem Zeitpunkt), Zielskripte werden nicht interaktiv ausgeführt.

Das Snippet muss

  • Geben Sie stdout zum Protokollieren aus und geben Sie immer ein Echo an die Konsole zurück
  • Geben Sie stderr zum Protokollieren und Echo zur Konsole aus, wenn das Debuggen aktiviert ist
  • stderr-Nachrichten sollten Zeitstempel und andere nützliche Informationen vorangestellt werden

Im Moment habe ich folgendes, das nur unter neueren Versionen von bash (4.2+?) Wie in Ubuntu präzise getestet wird, sich aber unter CentOS6 schlecht verhält.

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}

Dann das...

# 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
}

Stattdessen echokann ich eine dieser msg-Prozeduren aufrufen, z msg_con "hello world".
Außerdem wird die Skriptausgabe dann an stderr gesendet, indem zum Zeitpunkt des Aufrufs eine Umgebungsvariable festgelegt wird, z  DEBUG_TEST=true myscript.

Ich habe gelesen, dass exec in einigen Shells wie Busybox möglicherweise nicht funktioniert. Unter https://stackoverflow.com/a/5200754 gibt es eine Kombination aus mkfifo und Gabel , die etwas Ähnliches bewirkt, aber ich würde Gabel lieber nicht verwenden, es sei denn, dies wird unbedingt benötigt.

Bevorzugen Sie bitte Bash-Beispiele, aber etwas, das unter sh funktioniert oder tragbarer ist, wäre schön. Irgendwelche Ideen?

Glenn
quelle

Antworten:

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) ==="
}

Sie müssen $ logfile auf etwas gesetzt haben

Angelo
quelle
Das ist ein bisschen cool, so wie ich es lese, verwenden Sie gawk, um die Nachrichtenkopfzeilen hinzuzufügen. Dies hat den zusätzlichen Nebeneffekt, dass diese auch zu den Befehlsausgaben hinzugefügt werden.
Glenn
Der Grund für die Verwendung von gawk zum Hinzufügen eines Zeitstempels (und einer Prozess-ID) zu jeder Protokollzeile besteht darin, dass dieser bei jedem Schreiben der Ausgabe ausgeführt wird und daher der Zeitstempel aktualisiert wird. Es ist auch wichtig, gawk und nicht awk zu verwenden, da ich denke, dass die strftime-Funktion eine GNU-Erweiterung ist.
Angelo
0

exec > filenamesollte in sh funktionieren, und es funktioniert tatsächlich in Busybox v1.15.3 (Nov 2011). Die Prozessersetzung >(command)ist jedoch nicht portierbar, da es sich um eine Bash-Erweiterung handelt. Vermeiden Sie es einfach, es in Skripten zu verwenden. Warum >>reicht dir das nicht?

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

Eine andere Lösung besteht darin, die Umleitung außerhalb Ihrer Skripte anzugeben. Wenn Ihr Skript im Hintergrund aufgerufen wird (per Cron oder Systemskript usw.), sollten sie so aufgerufen werden

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

Wenn Sie das Skript manuell aufrufen und die Ausgabe anzeigen möchten, rufen Sie es einfach ohne Umleitungen auf.

kirikaza
quelle
1
Der Fragesteller möchte, dass die Ausgabe des Skripts sowohl an die Konsole als auch an die Protokolldatei gesendet wird.
0

Diese beiden Beispiele erfüllen Ihre erklärten Ziele

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

oder

echo -n $(date) >> $DEBUG_LOG
command >> $DEBUG_LOG 2>&1
Luke
quelle
0

Sie könnten teeBefehl oder scriptBefehl verwenden, beide sind wirklich nützlich.

Falk
quelle
Skript sieht cool aus, macht aber nicht wirklich das, was ich brauche, das Verhalten muss zur Laufzeit geändert werden.
Glenn