Wie die akzeptierte Antwort gut erklärt von lhunath können Sie verwenden
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
Wenn Sie die Bash verwenden, könnten Sie ein Problem bekommen .
Lassen Sie mich die matthew-wilcoxson Beispiel.
Und für diejenigen, die "sehen, was sie glauben", ein kurzer Test:
(echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
Wenn ich es persönlich versuche, habe ich dieses Ergebnis:
user@computer:~$ (echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
user@computer:~$ Test Out
Test Err
Beide Meldungen erscheinen nicht auf der gleichen Ebene. Warum wird Test Out
scheinen, wie wenn es mein vorheriger Befehl wäre?
Die Eingabeaufforderung steht in einer leeren Zeile, was mich glauben lässt, dass der Vorgang noch nicht abgeschlossen ist, und wenn ich auf Enter das bringt es in Ordnung. Wenn ich den Inhalt der Dateien überprüfe, ist er in Ordnung, und die Umleitung funktioniert.
Machen wir einen weiteren Test.
function outerr() {
echo "out" # stdout
echo >&2 "err" # stderr
}
user@computer:~$ outerr
out
err
user@computer:~$ outerr >/dev/null
err
user@computer:~$ outerr 2>/dev/null
out
Versuchen Sie erneut die Umleitung, aber mit dieser Funktion:
function test_redirect() {
fout="stdout.log"
ferr="stderr.log"
echo "$ outerr"
(outerr) > >(tee "$fout") 2> >(tee "$ferr" >&2)
echo "# $fout content: "
cat "$fout"
echo "# $ferr content: "
cat "$ferr"
}
Persönlich habe ich dieses Ergebnis:
user@computer:~$ test_redirect
$ outerr
# stdout.log content:
out
out
err
# stderr.log content:
err
user@computer:~$
Keine Eingabeaufforderung in einer leeren Zeile, aber ich sehe keine normale Ausgabe. Die stdout.log Inhalt scheinen falsch zu sein, und nur stderr.log scheint in Ordnung zu sein.
Wenn ich es neu starte, kann die Ausgabe unterschiedlich sein...
Und warum?
Weil, wie hier erklärt :
Beachten Sie, dass dieser Befehl in der Bash zurückkehrt, sobald [erster Befehl] beendet ist, auch wenn die Tee-Befehle noch ausgeführt werden (ksh und zsh warten auf die Unterprozesse)
Wenn Sie also Bash benutzen, verwenden Sie lieber das bessere Beispiel aus diese andere Antwort :
{ { outerr | tee "$fout"; } 2>&1 1>&3 | tee "$ferr"; } 3>&1 1>&2
Damit werden die bisherigen Probleme behoben.
Die Frage ist nun, wie man den Exit-Status-Code abrufen kann.
$?
funktioniert nicht.
Ich habe keine bessere Lösung gefunden, als Pipefail einzuschalten mit set -o pipefail
( set +o pipefail
zum Ausschalten) und verwenden Sie ${PIPESTATUS[0]}
wie diese:
function outerr() {
echo "out"
echo >&2 "err"
return 11
}
function test_outerr() {
local - # To preserve set option
! [[ -o pipefail ]] && set -o pipefail; # Or use second part directly
local fout="stdout.log"
local ferr="stderr.log"
echo "$ outerr"
{ { outerr | tee "$fout"; } 2>&1 1>&3 | tee "$ferr"; } 3>&1 1>&2
# First save the status or it will be lost
local status="${PIPESTATUS[0]}" # Save first, the second is 0, perhaps tee status code.
echo "==="
echo "# $fout content :"
echo "<==="
cat "$fout"
echo "===>"
echo "# $ferr content :"
echo "<==="
cat "$ferr"
echo "===>"
if (( status > 0 )); then
echo "Fail $status > 0"
return "$status" # or whatever
fi
}
user@computer:~$ test_outerr
$ outerr
err
out
===
# stdout.log content:
<===
out
===>
# stderr.log content:
<===
err
===>
Fail 11 > 0