2010-05-20 22 views
12

Me gustaría ejecutar varios comandos y capturar todos los resultados en un archivo de registro. También quiero imprimir cualquier error en la pantalla (u opcionalmente enviar la salida a alguien).Escribir STDOUT & STDERR en un archivo de registro, también escribir STDERR en la pantalla

Aquí hay un ejemplo. El siguiente comando ejecutará tres comandos y escribirá todos los resultados (STDOUT y STDERR) en un solo archivo de registro.

{ command1 && command2 && command3 ; } > logfile.log 2>&1 

Esto es lo que quiero hacer con la salida de estos comandos:

  • STDERR y stdout para todos los comandos va a un archivo de registro, en caso de que necesite más tarde --- Por lo general ganó mira aquí a menos que haya problemas.
  • Imprima STDERR en la pantalla (u opcionalmente, pipe to/bin/mail), para que cualquier error se destaque y no se ignore.
  • Sería bueno si los códigos de retorno aún pudieran utilizarse, para que yo pudiera hacer algún tipo de manejo de errores. Tal vez quiero enviar correo electrónico si hubo un error, así:

    {comando1 & & comando2 & & Command3; }> logfile.log 2> & 1 || mailx -s "Se ha producido un error" [email protected]~~V~~singular~~3rd

El problema me encuentro es que STDERR pierde contexto durante la redirección de E/S. A '2> & 1' convertirá STDERR en STDOUT, y por lo tanto no puedo ver los errores si hago 2> error.log

Aquí hay un par de ejemplos más jugosos. Vamos a pretender que estoy ejecutando algunos comandos de compilación familiares, pero no quiero que toda la construcción se detenga solo por un error, así que utilizo el indicador '--manejar'.

{ ./configure && make --keep-going && make install ; } > build.log 2>&1 

O, aquí hay un construir y desplegar script sencillo (y quizás descuidado), que seguir adelante en caso de un error.

{ ./configure && make --keep-going && make install && rsync -av --keep-going /foo devhost:/foo} > build-and-deploy.log 2>&1 

Creo que lo que quiero implica algún tipo de Bash I/O Redirection, pero no puedo resolver esto.

Respuesta

12
(./doit >> log) 2>&1 | tee -a log 

Esto tomará stdout y lo adjuntará al archivo de registro.

El stderr entonces pueden ser convertidos a la salida estándar, que se canaliza a tee que añade que en el registro (si se tienen Bash 4, puede reemplazar 2>&1 | con |&) y lo envía a la salida estándar que, o bien aparecerá en la TTY o se puede canalizar a otro comando.

He utilizado el modo de adición para ambos de modo que independientemente de qué orden la redirección de shell y tee abra el archivo, no se va a volar el original. Dicho esto, es posible que stderr/stdout esté intercalado de forma inesperada.

+0

Tu código funciona, pero tan pronto como ejecuto varios comandos como '(./doit && ./doit2 >> log) 2> & 1 | tee-a log', luego stdout y stderr para doit y doit2 se imprimen en la pantalla. –

+0

Esto parece funcionar si hago algo como esto: '({./doit && ./stdout.sh;} >> log) 2> & 1 | tee-log' –

+1

@StefanLasiewski - sí, la redirección de archivos solo se aplica al comando inmediatamente anterior. Su solución alternativa para agrupar los dos comandos en una sola subshell es la solución más fácil; otra solución más fea sería redirigir la salida estándar para cada comando '(./doit >> log && ./doit2 >> log) 2> & 1 | tee-log' –

0

Probar:

command 2>&1 | tee output.txt 

Además, puede dirigir stdout y stderr a diferentes lugares:

command > stdout.txt >& stderr.txt 

command > stdout.txt |& program_for_stderr 

Así que una combinación de lo anterior debe trabajar para usted - por ejemplo, puede guardar stdout en un archivo y stderr en un archivo y conectarlo a otro programa (con tee).

+1

Su primera línea está bien para el envío de stdout y stderr tanto el terminal como el archivo, pero las últimas dos líneas no funcionarán para enviarlas a diferentes lugares. El '> stdout.txt' termina sin tener efecto porque cuando usas'> & 'o' | & 'redirecciona _both_ streams. –

+0

Los primeros y terceros comandos no funcionarán, porque stderr se redirige a stdout mediante '2> & 1'. Esto es lo que quiero decir con "STDERR pierde contexto durante la redirección de E/S" arriba. El manual de referencia de Bash dice '| &' "es una abreviatura de' 2> & 1 | '. El segundo comando no imprime stderr en la pantalla. –

1

Si el sistema dispone de/dev/fd/* nodos que se pueden hacer como:

(exec 5>logfile.txt ; { command1 && command2 && command3 ;} 2>&1 >&5 | tee /dev/fd/5) 

Esto abre el archivo descriptor de 5 a su archivo de registro. Ejecuta los comandos con error estándar dirigido a out estándar, out estándar dirigido a fd 5 y pipes stdout (que ahora contiene solo stderr) a tee que duplica la salida a fd 5, que es el archivo de registro.

+0

Cuando ejecuto su comando, mi archivo de registro solo contiene los mensajes de error que veo en la pantalla. stdout está perdido. – tangens

+0

Pruebe 'tee -a/dev/fd/5' –

+0

Esto también funciona. Sin embargo, no estoy seguro de entender por qué. Pero probé un comando como este y funciona: '(exec 5> logfile.txt; {date && ./doit && ./stdout.sh;} 2> & 1> & 5 | tee/dev/fd/5) ' –

1

Aquí se explica cómo ejecutar uno o más comandos, capturando la salida estándar y el error en el orden en que se generaron, en un archivo de registro y mostrando solo el error estándar en la pantalla de terminal que desee. Funciona en Bash en Linux. Probablemente funciona en la mayoría de los otros entornos. Usaré un ejemplo para mostrar cómo se hace.

Preliminares:

Abra dos ventanas (conchas, sesiones TMux, lo que sea)

voy a demostrar con algunos archivos de prueba, por tanto, crear los archivos de prueba:

touch /tmp/foo /tmp/foo1 /tmp/foo2 

en window1:

mkfifo /tmp/fifo 

0</tmp/fifo cat - >/tmp/logfile 

Luego, en la ventana2:

(ls -l /tmp/foo /tmp/nofile /tmp/foo1 /tmp/nofile /tmp/nofile; echo successful test; ls /tmp/nofile1111) 2>&1 1>/tmp/fifo | tee /tmp/fifo 1>/dev/pts/2 

Donde reemplaza /dev/pts/2 con cualquier cosa que desee que se muestre el stderr.

El motivo de los diversos comandos exitosos y fallidos en la subshell es simplemente generar una secuencia mezclada de mensajes de salida y error, para que pueda verificar el orden correcto en el archivo de registro. Una vez que comprenda cómo funciona, reemplace los comandos "ls" y "echo" con scripts o comandos de su elección.

Con este método, se conserva el orden de salida y error, la sintaxis es simple y limpia, y solo hay una referencia única al archivo de salida. Además, hay flexibilidad en poner la copia adicional de stderr donde lo desee.

+0

Esto es esencialmente lo mismo que la respuesta de R Samuel Klatchkos arriba. No conserva el orden también. Pruébalo con un script simple à la 'echo out 1; echo err 2> & 2; echo out 3; echo err 4> & 2' en lugar de tu ls y verás. Supongo que su ejemplo funciona porque mientras ls se está iniciando, tee obtiene algunos ciclos de CPU, pero eso es pura suerte, con algo del mundo real esto no funcionaría. – Marian

+0

Voy a volver a realizar la prueba mañana, pero según recuerdo, ya hice algunas pruebas rigurosas la primera vez, incluido el eco y otros comandos, con resultados consistentes. –

0

añadir esto al comienzo de su script

#!/bin/bash 
set -e 
outfile=logfile 

exec > >(cat >> $outfile) 
exec 2> >(tee -a $outfile >&2) 

# write your code here 

STDOUT y STDERR se escribirá en $outfile, solamente STDERR se verá en la consola

Cuestiones relacionadas