Stderr-Ausgabe duplizieren und mit stderr in der Bash zusammenführen, ohne die Reihenfolge zu ändern

460
TPE

Ich möchte sowohl stderr als auch stdout in eine Protokolldatei schreiben und stderr auf das Terminal (oder das Standardausgabegerät) drucken.

Motivation: Ich habe einen Befehl in meiner crontab und möchte alle Ausgaben in einer Datei protokollieren. Ich möchte, dass cron mir eine E-Mail sendet, wenn etwas in die Fehlerausgabe geschrieben wird.

Ich hatte einige Erfolge mit diesen:

(echo out1; echo err1 1>&2; echo out2; echo err2 1>&2) \ 2> >(tee -a log) \ 1>>log 

Oder:

(echo err1 1>&2; echo out2; echo err2 1>&2) \ 3>&1 \ 1> >(tee -a log 1>/dev/null) \ 2> >(tee -a log 1>&3) 

Oder mit exec:

exec 3>&1 exec 1> >(tee -a log2 1>/dev/null) exec 2> >(tee -a log2 1>&3) echo out1; echo err1 1>&2; echo out2; echo err2 1>&2 

(Die dritte Lösung protokolliert auch die Eingabeaufforderung, sodass sie in einer interaktiven Shell nicht funktioniert.)

Das Problem bei allen drei Lösungen ist, dass die Protokolldatei die Zeilen in einer anderen Reihenfolge enthält:

out1 out2 err1 err2 

An Stelle von:

out1 err1 out2 err2 

Gibt es eine Möglichkeit, dies zu verhindern? So etwas 2>&1dupliziert die Ausgabe selbst und nicht den Deskriptor.

Für Windows gibt es eine sehr ähnliche Frage

2
Duplikat bei U & L: https://unix.stackexchange.com/questions/79996/how-to-redirect-stdout-and-stderr-to-a-file-and-display-stderr-to-console. Tomasz vor 6 Jahren 0
Ja, sorry, das habe ich nicht gefunden. Ich kann die Frage nicht als Duplikat kennzeichnen, da sich die andere Frage in einer anderen Domäne befindet. Was muss ich tun? Übrigens ist es für mich etwas überraschend, dass es für so etwas keine saubere Lösung gibt TPE vor 6 Jahren 0
Sie haben dieses nicht gepostet, es ist also kein Cross-Posting. Also keine Sorgen. Lass es einfach so wie es ist. Was die fragliche Angelegenheit angeht, so ist es nicht so überraschend, wie es scheinen mag. Es ist die Einfachheit. STDERR und STDOUT sind zwei verschiedene Kanäle, deren Synchronisierung Kosten verursachen würde. Sie können sich überlegen, wie sie nicht synchronisiert werden können, oder ob das allgemeine Protokoll auf ein Zeichen von Fehlern mit "grep" oder ähnlichem überprüft wird. Tomasz vor 6 Jahren 0

1 Antwort auf die Frage

0
Tomasz

Ich denke, Sie möchten dies so weit wie möglich vereinfachen und optimieren. Ich kann mir jetzt keine bessere Lösung vorstellen als Schritt für Schritt. Nämlich,

$ echo out1 >> log $ echo err1 | tee -a log >&2 err1 $ echo out2 >> log $ echo err2 | tee -a log >&2 err2 $ cat log out1 err1 out2 err2 

Nun, Sie könnten einen Coprocess verwenden, so dass Sie nicht mehrmals Tee anrufen müssen, wenn es Ihnen wichtig ist.

$ coproc tee -a log [1] 26417 $ echo out1 >> log $ echo err1 >&"$" $ echo out2 >> log $ echo err2 >&"$" $ cat log out1 err1 out2 err2 

Was auch immer die Fehler waren, sie warten in der Ausgabe-Pipeline des Coprocess. Wenn Sie nur prüfen müssen, ob etwas vorhanden ist, müssen Sie Folgendes tun:

$ timeout 1 head -n1 <&"$" >/dev/null && echo yes # or something else yes 

Wenn Sie die Fehler wiederverwenden möchten, können Sie den Coprozess an Ihr Ziel anpassen.

Sie können die Umleitung auch für Skripts und Binärdateien festlegen. Solange sie selbst keine festverdrahteten Weiterleitungen haben. So können Sie das tun,

$ some_executable 2>&"$" >>log 

Und die Logik bleibt gleich.

Das funktioniert und ist einfach zu tun, aber die Echo-Befehle sind nur Beispiele. Ich möchte die Umleitung mit installierten Skripten und Binärdateien von Drittanbietern verwenden. Sie wären auf diese Weise umständlich. Ich wusste nicht "coproc", es macht den Code schöner, scheint aber das oben genannte Problem nicht zu lösen. TPE vor 6 Jahren 0
@TPE Es spielt keine Rolle. Ich habe eine Erklärung beigefügt. Tomasz vor 6 Jahren 0
'' Sie können die Umleitung auch für Skripte und Binärdateien festlegen. '' Ich glaube nicht, dass dies funktioniert. Wenn die ausführbare Datei in einer bestimmten Reihenfolge sowohl in stdout als auch in stderr schreibt, werden sie trotzdem gemischt. TPE vor 6 Jahren 0
@TPE Hast du es ausprobiert? Tomasz vor 6 Jahren 0
Ja, ich habe die Echo-Befehle in ein `.sh`-Skript kopiert und auch ein einfaches C-Programm mit folgenden Ausgaben ausprobiert:` write (2, "err1 \ n", 5); ` TPE vor 6 Jahren 0
@TPE Ok. Dann ist es nicht so einfach. https://unix.stackexchange.com/questions/79996/how-to-redirect-stdout-and-stderr-to-a-file-and-display-stderr-to-console Tomasz vor 6 Jahren 0