Copie stdout y stderr en un archivo de registro y déjelos en la consola dentro del script

11

Con bash, ¿cómo copio stderr y stdout en un archivo de registro y también los dejo en la consola?

Me gustaría hacer esto dentro del script en sí usando un ejecutivo.

Lo intenté con

exec &>> log.out

echo "This is stdout"
echo "This is stderr" >&2

Pero lo anterior no imprime nada en la consola. ¿Cómo puedo lograr esto en bash?

adarshr
fuente
Hay una respuesta altamente votada a una pregunta similar en StackOverflow que responde a esta pregunta a fondo. stackoverflow.com/a/692407/208257
Dan Burton el

Respuestas:

10

Que busca tee.

Ver man teepara más detalles.

Para combinarlo exec, debe usar la sustitución del proceso . (Ver man bashpara más detalles).

exec &> >(tee  log.out)
echo "This is stdout"
echo "This is stderr" >&2
H.-Dirk Schmitt
fuente
Lo he mirado. Hacer exec 2>&1 | tee -a log.outsolo imprime en la consola, nada en el archivo de registro. ¿Quizás no estoy usando la sintaxis correcta?
adarshr
@adarshr Vuelva a verificar su código. He escrito sobre teeen combinación con la sustitución de procesos .
H.-Dirk Schmitt
1
Sin embargo, eso combina stdout y stderr y puede tener el mismo tipo de efecto secundario que se menciona en mi respuesta.
Stéphane Chazelas
@StephaneChazelas Mira el código de ejemplo en la pregunta: esa fue la intención del OP.
H.-Dirk Schmitt
Lo que quiero decir con fusión es que ahora los errores del script van a stdout. Entonces, si alguien lo hace, the-script | wc -lpor ejemplo, eso también contará las líneas de error y no verá los errores.
Stéphane Chazelas
5

Tu puedes hacer:

: > log # empty log file if necessary
{ { {

  ...the script

} 3>&- | tee -a log >&3 3>&-
exit "${PIPESTATUS[0]}"
} 2>&1 | tee -a log >&2 3>&-
} 3>&1
exit "${PIPESTATUS[0]}"

También puedes escribirlo como:

: > log # empty log file if necessary
exec 2> >(tee -a log >&2) > >(tee -a log)

...the script

Pero debido a que bash no está esperando que esos procesos comiencen >(...), eso tiene el efecto desagradable de algunas veces enviar algo al terminal después de que el comando ha regresado, lo que puede tener efectos aún más desagradables (como descartar silenciosamente esa salida) si el atributo "tostop" del terminal Está encendido.

En cualquier caso, al hacer stdoutuna tubería en ambas soluciones, y debido a que dos comandos emiten de forma independiente los mensajes de salida y error, esto afectará el almacenamiento intermedio de salida y el orden en que se muestran los mensajes de salida y error.

Stéphane Chazelas
fuente
Creo que a tu segundo tee le falta una redirección a stderr. Debería ser:tee -a log >&2 3>&-
richvdh
5

Sé que esta es una publicación antigua, pero ¿por qué no hacer esto?

echo "hi" >> log.txt #stdout -> log
echo "hi" | tee -a log.txt #stdout -> log & stdout
echo "hi" &>> log.txt #stdout & stderr -> log
echo "hi" |& tee -a log.txt #stdout & stderr -> log & stdout

Y, por supuesto, si desea stdout, puede imprimir regularmente.

Puede hacer esto con cualquier combinación de secuencias que desee, simplemente usando esos dos comandos básicos.

Sé que vine aquí y no obtuve una respuesta fácil de entender / implementar, espero que esto sea de ayuda para alguien más que está luchando.

Por cierto, para novatos como mi yo anterior, todo lo que hace el teecomando es enviar la entrada stdin tanto a stdout como a los archivos especificados como argumentos posteriores. -asignifica anexar, por lo que no sobrescribe el archivo con cada uso del comando. Si tiene más preguntas, creo que este es un recurso muy útil para aprender rápidamente bash.

usuario2624583
fuente
1
Gracias por contribuir Yo, por otra parte, totalmente olvidado lo que estaba tratando de hacer :-)
adarshr
1
+1 por dar ejemplos de tee múltiples, agradables y simples.
Tim
2

Una forma más de hacerlo es usar redirecciones dentro de las funciones.

#!/bin/bash

function1 () {
    echo 'STDOUT from function 1'
    echo 'STDERR from function 1' >&2
}

function2 () {
    echo 'STDOUT from function 2'
    echo 'STDERR from function 2' >&2
}


function3 () {
    echo 'STDOUT from function 3'
    echo 'STDERR from function 3' >&2
}

main() {
    function1
    function2
    function3
}

main 2>&1 |tee log.txt

Aquí tenemos una mainfunción que invoca todas las demás funciones. Ahora redireccionando STDOUTy STDERRde mainfunción a tee.

Kannan Mohan
fuente
En mi humilde opinión, esta es la forma más limpia de hacerlo, al menos para casos simples. Gracias.
ACK_stoverflow