Ist es möglich, die gesamte Ausgabe eines Bourne-Shell-Skripts an einen anderen Ort umzuleiten, jedoch mit Shell-Befehlen im Skript selbst?
Das Umleiten der Ausgabe eines einzelnen Befehls ist einfach, aber ich möchte mehr davon:
#!/bin/sh
if [ ! -t 0 ]; then
# redirect all of my output to a file here
fi
# rest of script...
Das heißt: Wenn das Skript nicht interaktiv ausgeführt wird (z. B. cron), speichern Sie die Ausgabe von allem in einer Datei. Wenn Sie interaktiv von einer Shell aus ausführen, lassen Sie die Ausgabe wie gewohnt auf stdout gehen.
Ich möchte dies für ein Skript tun, das normalerweise vom periodischen Dienstprogramm FreeBSD ausgeführt wird. Es ist Teil des täglichen Laufs, den ich normalerweise nicht jeden Tag per E-Mail sehen möchte, daher habe ich ihn nicht gesendet. Wenn jedoch etwas in diesem einen bestimmten Skript fehlschlägt, ist das für mich wichtig und ich möchte in der Lage sein, die Ausgabe dieses einen Teils der täglichen Jobs zu erfassen und per E-Mail zu versenden.
Update: Joshuas Antwort ist genau richtig, aber ich wollte auch stdout und stderr für das gesamte Skript speichern und wiederherstellen, was folgendermaßen gemacht wird:
# save stdout and stderr to file descriptors 3 and 4, then redirect them to "foo"
exec 3>&1 4>&2 >foo 2>&1
# ...
# restore stdout and stderr
exec 1>&3 2>&4
exec 1>&3 2>&4 3>&- 4>&-
Antworten:
Beantwortung der Frage als aktualisiert.
Die geschweiften Klammern '{...}' bieten eine Einheit für die E / A-Umleitung. Die geschweiften Klammern müssen dort erscheinen, wo ein Befehl erscheinen könnte - vereinfacht, am Anfang einer Zeile oder nach einem Semikolon. ( Ja, das kann präzisiert werden. Wenn Sie streiten möchten, lassen Sie es mich wissen. )
Sie haben Recht, dass Sie das ursprüngliche stdout und stderr mit den von Ihnen angezeigten Weiterleitungen beibehalten können, aber es ist normalerweise einfacher für die Personen, die das Skript später warten müssen, zu verstehen, was vor sich geht, wenn Sie den umgeleiteten Code wie oben gezeigt in den Geltungsbereich aufnehmen.
Die relevanten Abschnitte des Bash-Handbuchs sind Gruppierungsbefehle und E / A-Umleitung . Die relevanten Abschnitte der POSIX-Shell-Spezifikation sind zusammengesetzte Befehle und E / A-Umleitung . Bash hat einige zusätzliche Notationen, ähnelt aber ansonsten der POSIX-Shell-Spezifikation.
quelle
>>
. Einige Leute haben die Angewohnheit von>
. Das Anhängen ist immer sicherer und empfehlenswerter als das Überwinden. Jemand hat eine Anwendung geschrieben, die den Standardkopierbefehl verwendet, um einige Daten an dasselbe Ziel zu exportieren.Normalerweise platzieren wir eine davon am oder nahe dem oberen Rand des Skripts. Skripte, die ihre Befehlszeilen analysieren, führen die Umleitung nach dem Parsen durch.
Senden Sie stdout an eine Datei
mit stderr
Hängen Sie sowohl stdout als auch stderr an die Datei an
Wie Jonathan Leffler in seinem Kommentar erwähnte :
exec
hat zwei getrennte Jobs. Die erste besteht darin, die aktuell ausgeführte Shell (Skript) durch ein neues Programm zu ersetzen. Das andere ist das Ändern der E / A-Umleitungen in der aktuellen Shell. Dies zeichnet sich dadurch aus, dass kein Argument dafür vorliegtexec
.quelle
exec
hat zwei separate Jobs. Eine besteht darin, das aktuelle Skript mit demselben Prozess durch einen anderen Befehl zu ersetzen. Sie geben den anderen Befehl als Argument anexec
(und Sie können die E / A-Umleitungen dabei anpassen). Der andere Job besteht darin, die E / A-Umleitungen im aktuellen Shell-Skript zu ändern, ohne es zu ersetzen. Diese Notation zeichnet sich dadurch aus, dass kein Befehl als Argument für vorhanden istexec
. Die Notation in dieser Antwort ist die Variante "Nur E / A" - sie ändert nur die Umleitung und ersetzt nicht das Skript, das ausgeführt wird. (Derset
Befehl ist ähnlich vielseitig.)exec > >(tee -a "logs/logdata.log") 2>&1
druckt die Protokolle auf dem Bildschirm und schreibt sie in eine DateiSie können das gesamte Skript wie folgt einrichten:
Dann haben Sie am Ende des Skripts Folgendes:
Alternativ können Sie bei jedem Lauf alles in die Protokolldatei einloggen und es dennoch an stdout ausgeben, indem Sie einfach Folgendes tun:
quelle
Zum Speichern des ursprünglichen stdout und stderr können Sie verwenden:
Der folgende Code druckt beispielsweise "walla1" und "walla2" in die Protokolldatei (
a.txt
), "walla3" in stdout und "walla4" in stderr.quelle
exec 5>&1
undexec 6>&2
, die Umleitung der Ausgabe Notation anstatt Eingabeumleitung Notation für die Ausgänge. Sie kommen damit durch, denn wenn das Skript von einem Terminal ausgeführt wird, ist auch die Standardeingabe beschreibbar und sowohl die Standardausgabe als auch der Standardfehler sind aufgrund einer historischen Eigenart lesbar (oder ist es "Laster"?): Das Terminal ist geöffnet für Lesen und Schreiben sowie dieselbe Beschreibung der geöffneten Datei werden für alle drei Standard-E / A-Dateideskriptoren verwendet.quelle