Wie kann ich stdout in einer Datei, stderr in einer anderen Datei, stdout+stderr in einer dritten Datei speichern und außerdem stdout + stderr wie üblich für ein Shell-Skript zum Terminal bringen?
Ich habe das hier woanders gefunden:
exec > >(tee std_out) 2> >(tee err_out >&2)
ls # Should got to std_out
fsdfs # Command not found goes to err_out
Das ist wirklich nah dran. Wenn ich bash test.sh 2>&1 | tee output
es ausführe, funktioniert es, aber ich habe keinen Zugriff darauf, wie mein Skript ausgeführt wird. Es ist ein CICD-System. Ich muss in der Lage sein, die „kombinierte Ausgabe“ aus dem Skript heraus mit exec zu erstellen.
Ich erstelle eine CI/CD-Bibliothek und weiß nicht, wofür die Clients die Bibliothek verwenden würden. Deshalb möchte ich jeden Anwendungsfall berücksichtigen.
Antwort1
Erweitern Sie einfach Ihren Ansatz:
exec 2> >(tee -a stderr stdall) 1> >(tee -a stdout stdall)
Der Standardfehler wird in die Datei mit dem Namen geschrieben stderr
, die Standardausgabe in stdout
und sowohl der Standardfehler als auch die Standardausgabe werden auch in die Konsole geschrieben (oder worauf auch immer die beiden Dateideskriptoren zum Zeitpunkt exec
der Ausführung zeigen) und in stdall
. (Anhängen) ist erforderlich, um ein Überschreiben durch den Sekundenzeiger zu
tee -a
verhindern , der mit dem Schreiben dorthin beginnt.stdall
tee
Beachten Sie, dassdie Bestellungin denen Umleitungen durchgeführt werden, ist relevant: Die zweite Prozessersetzung wird von der ersten Umleitung beeinflusst, d. h. die von ihr ausgegebenen Fehler würden an gesendet >(tee -a stderr stdall)
. Sie können die Standardfehlerausgabe der zweiten Prozessersetzung natürlich an umleiten, um /dev/null
diesen Nebeneffekt zu vermeiden. Eine Umleitung der Standardausgabe vor der Standardfehlerausgabe würde alle Fehler auch an stdout
und senden stdall
.
Da die Befehle in Bashs Prozesssubstitutionen ausgeführt werdenasynchron, gibt es keine Garantie dafür, dass die Ausgabe in der Reihenfolge angezeigt wird, in der sie generiert wurde. Schlimmer noch: Fragmente der Standardausgabe und der Standardfehlerausgabe erscheinen wahrscheinlich in derselben Zeile.
Antwort2
Ihr Skript kann sich selbst vollständig ausführen $0
(mit Festlegen und Überprüfen einer Umgebungsvariablen, um eine Endlosschleife zu vermeiden), anstatt sich auf > >(...)
die Konstruktion von Bash zu verlassen, die laut IMLE kapriziös und unzuverlässig ist.
if [ "$REDIRECTED" != 1 ]; then
export REDIRECTED=1
set -o pipefail
{ { "$0" | tee stdout >&3; } 2>&1 | tee stderr; } 3>&1 | tee stdboth
exit
fi
# rest of your script here
Da tee
keine Zeilenpufferung verwendet (und dies auch nicht mit erzwungen werden kann stdbuf(1)
), wird die Reihenfolge der in stdout und stderr geschriebenen Daten in der endgültigen Ausgabe nicht beachtet. Bei einem Befehl, der die vollständige Pufferung verwendet und sowohl in stdout als auch in stderr schreibt, hilft nicht einmal eine Zeilenpufferung, tee
und schlimmer noch, Sie erhalten möglicherweise Ausgabezeilen, die zur Hälfte aus stdout und zur Hälfte aus stderr bestehen.
Ich glaube nicht, dass es dafür eine Lösung gibt, wenn man nur die Shell-Sprache und leicht verfügbare Befehlszeilen-Dienstprogramme verwendet.
Antwort3
Ich erstelle eine CI/CD-Bibliothek und weiß nicht, wofür die Clients die Bibliothek verwenden würden. Deshalb möchte ich jeden Anwendungsfall berücksichtigen.
Ich stelle die Notwendigkeit von Bash zur Verarbeitung der Ausgaben in Frage, da dies das Szenario ist. Idealerweise möchten Sie in diesem Zusammenhang die Ausgabe mit einem Zeitstempel versehen und ihr eine ID für den Standardausgabetyp zuweisen, und die Anwendung sollte diejenige sein, die entscheidet, was mit den Nachrichten zu tun ist.