¿Cómo escribo un error estándar en un archivo mientras uso "tee" con una tubería?
Sé cómo usarlo tee
para escribir la salida ( salida estándar ) de aaa.sh
to bbb.out
, mientras sigo mostrándola en la terminal:
./aaa.sh | tee bbb.out
¿Cómo podría escribir ahora también un error estándar en un archivo llamado ccc.out
, sin dejar de mostrarlo?
Supongo que aún desea ver el error estándar y la salida estándar en el terminal. Podrías optar por la respuesta de Josh Kelley , pero encuentro que mantener un tail
entorno en segundo plano genera tu archivo de registro muy complicado y complicado. Observe cómo necesita mantener un descriptor de archivo adicional y luego realizar una limpieza eliminándolo y técnicamente debería hacerlo en un archivo trap '...' EXIT
.
Hay una manera mejor de hacer esto y ya la has descubierto: tee
.
Solo que, en lugar de usarlo simplemente para la salida estándar, tenga una T para la salida estándar y otra para el error estándar. ¿Cómo lograrás esto? Sustitución de procesos y redirección de archivos:
command > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
Dividámoslo y expliquemos:
> >(..)
>(...)
(sustitución de procesos) crea un FIFO y tee
lo escuchamos. Luego, utiliza >
(redirección de archivos) para redirigir la salida estándar command
al FIFO en el que tee
está escuchando el primero.
Lo mismo para el segundo:
2> >(tee -a stderr.log >&2)
Usamos la sustitución de procesos nuevamente para crear un tee
proceso que lea la entrada estándar y la descargue en stderr.log
. tee
devuelve su entrada a la salida estándar, pero dado que su entrada es nuestro error estándar, queremos redirigir tee
la salida estándar a nuestro error estándar nuevamente. Luego usamos la redirección de archivos para redirigir command
el error estándar a la entrada FIFO ( tee
entrada estándar de).
Ver entrada y salida
La sustitución de procesos es una de esas cosas realmente hermosas que obtienes como beneficio adicional al elegir Bash como tu shell en lugar de sh
(POSIX o Bourne).
En sh
, tendrías que hacer las cosas manualmente:
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"
Simplemente:
./aaa.sh 2>&1 | tee -a log
Esto simplemente redirige el error estándar a la salida estándar, por lo que tee hace eco tanto en el registro como en la pantalla. Quizás me estoy perdiendo algo, porque algunas de las otras soluciones parecen realmente complicadas.
Nota: Desde la versión 4 de Bash, puede utilizar |&
como abreviatura 2>&1 |
:
./aaa.sh |& tee -a log
Esto puede resultar útil para las personas que encuentran esto a través de Google. Simplemente descomente el ejemplo que desea probar. Por supuesto, siéntase libre de cambiar el nombre de los archivos de salida.
#!/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}