Ich kann tee
verwenden, um die Ausgabe (STDOUT
) von aaa.sh
In bbb.out
Zu schreiben, während es weiterhin im Terminal angezeigt wird:
./aaa.sh | tee bbb.out
Wie würde ich jetzt auch STDERR
in eine Datei mit dem Namen ccc.out
Schreiben, während sie noch angezeigt wird?
Ich gehe davon aus, dass Sie STDERR und STDOUT weiterhin auf dem Terminal sehen möchten. Sie könnten sich für Josh Kelleys Antwort entscheiden, aber ich finde, dass es im Hintergrund ein tail
gibt, das Ihre Protokolldatei sehr kitschig und klobig ausgibt. Beachten Sie, wie Sie eine exra-FD behalten und anschließend bereinigen müssen, indem Sie sie töten. Technisch gesehen sollten Sie dies in einem trap '...' EXIT
Tun.
Es gibt einen besseren Weg, dies zu tun, und Sie haben es bereits entdeckt: tee
.
Nur, anstatt es nur für Ihre stdout zu verwenden, haben Sie ein T-Stück für stdout und eins für stderr. Wie werden Sie das erreichen? Prozessersetzung und Dateiumleitung:
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
Teilen wir es auf und erklären:
> >(..)
>(...)
(Prozessersetzung) erstellt ein FIFO und lässt tee
darauf hören. Dann verwendet es >
(Dateiumleitung) zu Leiten Sie das STDOUT von command
zu dem FIFO, das Ihr erstes tee
abhört.
Gleiches für die Sekunde:
2> >(tee -a stderr.log >&2)
Wir verwenden die Prozessersetzung erneut, um einen tee
-Prozess zu erstellen, der aus STDIN liest und in stderr.log
Speichert. tee
gibt seine Eingabe wieder auf STDOUT aus, aber da seine Eingabe unser STDERR ist, möchten wir das STDOUT von tee
wieder auf unser STDERR umleiten. Dann verwenden wir die Dateiumleitung, um STDERR von command
zum Eingang des FIFO umzuleiten (STDIN von tee
).
Siehe http://mywiki.wooledge.org/BashGuide/InputAndOutput
Prozessersetzung ist eine dieser wirklich schönen Dinge, die Sie als Bonus erhalten, wenn Sie bash
als Ihre Shell auswählen, im Gegensatz zu sh
(POSIX oder Bourne).
In sh
müssten Sie die Dinge manuell erledigen:
out="${TMPDIR:-/tmp}/out.$$" err="${TMPDIR:-/tmp}/err.$$"
mkfifo "$out" "$err"
trap 'rm "$out" "$err"' EXIT
tee -a stdout.log < "$out" &
tee -a stderr.log < "$err" >&2 &
command >"$out" 2>"$err"
warum nicht einfach:
./aaa.sh 2>&1 | tee -a log
Dies leitet einfach stderr
zu stdout
um, sodass das Echo sowohl zum Protokollieren als auch zum Anzeigen von Meldungen erfolgt. Vielleicht fehlt mir etwas, weil einige der anderen Lösungen wirklich kompliziert erscheinen.
Anmerkung: Seit der Bash-Version 4 können Sie |&
als Abkürzung für 2>&1 |
:
./aaa.sh |& tee -a log
Dies kann nützlich sein, wenn Sie dies über Google finden. Deaktivieren Sie einfach das Beispiel, das Sie ausprobieren möchten. Natürlich können Sie die Ausgabedateien auch umbenennen.
#!/bin/bash
STATUSFILE=x.out
LOGFILE=x.log
### All output to screen
### Do nothing, this is the default
### All Output to one file, nothing to the screen
#exec > ${LOGFILE} 2>&1
### All output to one file and all output to the screen
#exec > >(tee ${LOGFILE}) 2>&1
### All output to one file, STDOUT to the screen
#exec > >(tee -a ${LOGFILE}) 2> >(tee -a ${LOGFILE} >/dev/null)
### All output to one file, STDERR to the screen
### Note you need both of these lines for this to work
#exec 3>&1
#exec > >(tee -a ${LOGFILE} >/dev/null) 2> >(tee -a ${LOGFILE} >&3)
### STDOUT to STATUSFILE, stderr to LOGFILE, nothing to the screen
#exec > ${STATUSFILE} 2>${LOGFILE}
### STDOUT to STATUSFILE, stderr to LOGFILE and all output to the screen
#exec > >(tee ${STATUSFILE}) 2> >(tee ${LOGFILE} >&2)
### STDOUT to STATUSFILE and screen, STDERR to LOGFILE
#exec > >(tee ${STATUSFILE}) 2>${LOGFILE}
### STDOUT to STATUSFILE, STDERR to LOGFILE and screen
#exec > ${STATUSFILE} 2> >(tee ${LOGFILE} >&2)
echo "This is a test"
ls -l sdgshgswogswghthb_this_file_will_not_exist_so_we_get_output_to_stderr_aronkjegralhfaff
ls -l ${0}
Um stderr in eine Datei umzuleiten, zeigen Sie stdout auf dem Bildschirm an und speichern Sie stdout in einer Datei:
./aaa.sh 2> ccc.out | tee ./bbb.out
[~ # ~] edit [~ # ~] : Um sowohl stderr als auch stdout auf dem Bildschirm anzuzeigen und beide in einer Datei zu speichern, können Sie bash verwenden E/A-Umleitung :
#!/bin/bash
# Create a new file descriptor 4, pointed at the file
# which will receive stderr.
exec 4<>ccc.out
# Also print the contents of this file to screen.
tail -f ccc.out &
# Run the command; tee stdout as normal, and send stderr
# to our file descriptor 4.
./aaa.sh 2>&4 | tee bbb.out
# Clean up: Close file descriptor 4 and kill tail -f.
exec 4>&-
kill %1
Mit anderen Worten, Sie möchten stdout in einen Filter (tee bbb.out
) Und stderr in einen anderen Filter (tee ccc.out
) Leiten. Es gibt keine Standardmethode, um etwas anderes als stdout in einen anderen Befehl umzuleiten, aber Sie können das umgehen, indem Sie Dateideskriptoren jonglieren.
{ { ./aaa.sh | tee bbb.out; } 2>&1 1>&3 | tee ccc.out; } 3>&1 1>&2
Siehe auch Wie greife ich auf den Standardfehlerstrom (stderr)? und Wann würden Sie einen zusätzlichen Dateideskriptor verwenden?
In bash (und ksh und zsh), aber nicht in anderen POSIX-Shells wie dash, können Sie Prozessersetzung verwenden:
./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out)
Beachten Sie, dass dieser Befehl in bash zurückgegeben wird, sobald ./aaa.sh
Beendet ist, auch wenn die Befehle tee
noch ausgeführt werden (ksh und zsh warten auf die Unterprozesse). Dies kann ein Problem sein, wenn Sie etwas wie ./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out); process_logs bbb.out ccc.out
ausführen. Verwenden Sie in diesem Fall stattdessen File Descriptor Jonglage oder ksh/zsh.
Wenn Sie bash verwenden:
# Redirect standard out and standard error separately
% cmd >stdout-redirect 2>stderr-redirect
# Redirect standard error and out together
% cmd >stdout-redirect 2>&1
# Merge standard error with standard out and pipe
% cmd 2>&1 |cmd2
Das Guthaben (das nicht von oben beantwortet wird) finden Sie hier: http://www.cygwin.com/ml/cygwin/2003-06/msg00772.html
Das Folgende funktioniert für KornShell (ksh), wo die Prozessersetzung nicht verfügbar ist.
# create a combined(stdin and stdout) collector
exec 3 <> combined.log
# stream stderr instead of stdout to tee, while draining all stdout to the collector
./aaa.sh 2>&1 1>&3 | tee -a stderr.log 1>&3
# cleanup collector
exec 3>&-
Der eigentliche Trick dabei ist die Folge von 2>&1 1>&3
, Die in unserem Fall den stderr
zu stdout
und den stdout
zum Deskriptor 3
. Zu diesem Zeitpunkt sind stderr
und stdout
noch nicht kombiniert.
Tatsächlich wird das stderr
(als stdin
) an tee
übergeben, wo es sich bei stderr.log
Anmeldet und auch zu Deskriptor 3 umleitet.
Und der Deskriptor 3
Zeichnet es die ganze Zeit auf combined.log
Auf. Das combined.log
Enthält also sowohl stdout
als auch stderr
.
In meinem Fall hat ein Skript einen Befehl ausgeführt, während sowohl stdout als auch stderr in eine Datei umgeleitet wurden.
cmd > log 2>&1
Ich musste es so aktualisieren, dass bei einem Fehler einige Maßnahmen basierend auf den Fehlermeldungen ergriffen werden. Ich könnte natürlich das dup entfernen 2>&1
und erfassen Sie das stderr aus dem Skript, aber dann werden die Fehlermeldungen nicht als Referenz in die Protokolldatei aufgenommen. Während die akzeptierte Antwort von @lhunath dasselbe tun soll, leitet sie stdout
und stderr
zu verschiedenen Dateien um, was nicht das ist, was ich will, aber es hat mir geholfen, das genaue zu finden Lösung, die ich brauche:
(cmd 2> >(tee /dev/stderr)) > log
Mit den oben genannten Optionen verfügt log über eine Kopie von stdout
und stderr
, und ich kann stderr
aus meinem Skript erfassen, ohne mich um stdout
kümmern zu müssen.