Předpokládám, že chcete na terminálu stále vidět STDERR a STDOUT. Můžete jít po odpovědi Joshe Kelleyho, ale zjistil jsem, že si nechávám tail
kolem na pozadí, což vypíše váš log soubor velmi hackerský a neohrabaný. Všimněte si, jak si musíte ponechat exra FD a poté provést vyčištění jeho zabitím a technicky by to mělo být provedeno v trap '...' EXIT
.
Existuje lepší způsob, jak to udělat, a už jste ho objevili:tee
.
Pouze místo toho, abyste jej používali pouze pro svůj stdout, mějte tričko pro stdout a jedno pro stderr. Jak toho dosáhnete? Nahrazení procesu a přesměrování souboru:
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
Pojďme si to rozdělit a vysvětlit:
> >(..)
>(...)
(záměna procesu) vytvoří FIFO a nechá tee
poslouchej to. Potom použije >
(přesměrování souboru) k přesměrování STDOUT z command
na FIFO, že vaše první tee
poslouchá dál.
Totéž pro druhou:
2> >(tee -a stderr.log >&2)
K vytvoření tee
opět použijeme substituci procesů proces, který čte ze STDIN a ukládá jej do stderr.log
. tee
odešle svůj vstup zpět na STDOUT, ale protože jeho vstup je náš STDERR, chceme přesměrovat tee
's STDOUT do našeho STDERR znovu. Pak použijeme přesměrování souboru k přesměrování command
's STDERR na vstup FIFO (tee
STDIN).
Viz http://mywiki.wooledge.org/BashGuide/InputAndOutput
Náhrada procesů je jedna z těch opravdu krásných věcí, které získáte jako bonus za volbu bash
jako váš shell na rozdíl od sh
(POSIX nebo Bourne).
V sh
, budete muset dělat věci ručně:
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"
proč ne jednoduše:
./aaa.sh 2>&1 | tee -a log
Toto jednoduše přesměruje stderr
na stdout
, takže tee se ozývá jak do logu, tak do obrazovky. Možná mi něco uniká, protože některá další řešení se zdají být opravdu složitá.
Poznámka: Od verze bash 4 můžete používat |&
jako zkratka pro 2>&1 |
:
./aaa.sh |& tee -a log
To může být užitečné pro lidi, kteří to najdou přes google. Jednoduše odkomentujte příklad, který chcete vyzkoušet. Samozřejmě můžete výstupní soubory přejmenovat.
#!/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}