2008-11-24 26 views
119

¿Es posible redirigir todo el resultado de un script de Bourne shell a alguna parte, pero con comandos de shell dentro del script?¿Cómo redirecciono el resultado de un script de shell completo dentro del script?

Redirigir la salida de un solo comando es fácil, pero quiero algo más parecido a esto:

#!/bin/sh 
if [ ! -t 0 ]; then 
    # redirect all of my output to a file here 
fi 

# rest of script... 

Significado: si el script se ejecuta de forma no interactiva (por ejemplo, cron), guardar fuera de la salida de todo a un archivo. Si se ejecuta interactivamente desde un shell, deje que la salida pase a stdout como de costumbre.

Quiero hacer esto para un script normalmente ejecutado por la utilidad periódica de FreeBSD. Es parte de la ejecución diaria, que normalmente no me interesa ver todos los días en el correo electrónico, por lo que no la envío. Sin embargo, si algo dentro de este script en particular falla, eso es importante para mí y me gustaría poder capturar y enviar por correo electrónico el resultado de esta parte de los trabajos diarios.

Actualización: La respuesta de Joshua está en el lugar, pero yo también quería salvar y restaurar stdout y stderr alrededor de toda la secuencia de comandos, que se realiza de esta manera:

# save stdout and stderr to file descriptors 3 and 4, then redirect them to "foo" 
exec 3>&1 4>&2 >foo 2>&1 

# ... 

# restore stdout and stderr 
exec 1>&3 2>&4 
+2

Pruebas de $ plazo no es la mejor manera de probar para el modo interactivo. En su lugar, compruebe si stdin es un tty (test -t 0). –

+2

En otras palabras: si [! -t 0]; luego exec> somefile 2> & 1; fi –

+0

Vea aquí para obtener toda la bondad: [http://tldp.org/LDP/abs/html/io-redirection.html](http://tldp.org/LDP/abs/html/io-redirection.html) Básicamente lo que dijo Joshua. El archivo exec> redirige stdout a un archivo específico, exec Loki

Respuesta

107

Enviar la salida estándar a un archivo

exec > file 

con stderr

exec > file                  
exec 2>&1 

append stdout y stderr a presentar

exec >> file 
exec 2>&1 
+7

Digo también agregue 2> & 1 hasta el final de eso, solo stderr queda atrapado también :-) –

+1

Insignia iluminada para el arma más rápida en el oeste hace años. – Joshua

+0

No tienes idea de cuántas insignias Iluminadas obtuve de esa manera. :-P –

20

Usted puede hacer todo el guión de una función como esta:

main_function() { 
    do_things_here 
} 

luego, al final de la secuencia de comandos tiene esto:

if [ -z $TERM ]; then 
    # if not run via terminal, log everything into a log file 
    main_function 2>&1 >> /var/log/my_uber_script.log 
else 
    # run via terminal, only output to screen 
    main_function 
fi 

Alternativamente, es posible registrar todo en el archivo de registro cada ejecución y todavía lo produce en stdout simplemente haciendo:

# log everything, but also output to stdout 
main_function 2>&1 | tee -a /var/log/my_uber_script.log 
+0

Quizás quiso decir main_function >> /var/log/my_uber_script.log 2> & 1 –

+0

Me gusta usar main_function en dicha tubería. Pero en este caso su script no devuelve el valor de retorno original. En caso de bash, debe salir y luego usar 'exit $ {PIPESTATUS [0]}'. – rudimeier

87

Cómo responder la pregunta tal como se actualizó.

#...part of script without redirection... 

{ 
    #...part of script with redirection... 
} > file1 2>file2 # ...and others as appropriate... 

#...residue of script without redirection... 

Las llaves '{...}' proporcionan una unidad de redirección de E/S. Las llaves deben aparecer donde podría aparecer un comando, de manera simplista, al comienzo de una línea o después de un punto y coma. (Sí, que se pueden hacer más precisa; si desea objetar, que me haga saber.)

Tienes razón en que se puede preservar la salida estándar original y stderr con las redirecciones que apareciste, pero por lo general es más sencillo para las personas que tienen que mantener el script más adelante para comprender lo que sucede si se analiza el código redirigido como se muestra arriba.

+3

Esto es mucho más claro que guardar los descriptores originales y restaurarlos más tarde. –

+13

Tuve que hacer un poco de google para entender lo que realmente está haciendo, así que quería compartir. Las llaves se convierten en un ["bloque de código"] (http://www.tldp.org/LDP/abs/html/special-chars.html#CODEBLOCKREF), que, en efecto, crea una _función anónima_. El resultado de todo en el bloque de código se puede redireccionar (ver ** Ejemplo 3-2 ** de ese enlace). También tenga en cuenta que las llaves _do no_ lanzan una [subshell] (http://www.tldp.org/LDP/abs/html/subshells.html), pero similares [redireccionamientos de E/S] (http: // www .tldp.org/LDP/abs/html/ioredirintro.html) _can_ hacerse con subcapas usando paréntesis. – chris

+1

Me gusta esta solución mejor que las demás.Incluso una persona con la comprensión más básica de la redirección de E/S puede entender lo que está sucediendo. Además, es más detallado. Y, como Pythoner, me encanta lo detallado. –

2
[ -t <&0 ] || exec >> test.log 
2

Para guardar la salida estándar original y stderr puede utilizar:

exec [fd number]<&1 
exec [fd number]<&2 

Por ejemplo, el código siguiente imprimirá "walla1" y "walla2" para el archivo de registro (a.txt) ", walla3 "a stdout", walla4 "a stderr.

#!/bin/bash 

exec 5<&1 
exec 6<&2 

exec 1> ~/a.txt 2>&1 

echo "walla1" 
echo "walla2" >&2 
echo "walla3" >&5 
echo "walla4" >&6 
+1

Normalmente, sería mejor usar 'exec 5> & 1' y' exec 6> & 2', utilizando la notación de redirección de salida en lugar de la notación de redirección de entrada para las salidas. Se sale con la suya porque cuando el script se ejecuta desde un terminal, la entrada estándar también se puede escribir y tanto la salida estándar como el error estándar son legibles por virtud (¿o es 'vicio'?) De una peculiaridad histórica: el terminal se abre para lectura y escritura y lo mismo [descripción de archivo abierto] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html) se usa para los tres descriptores de archivos de E/S estándar. –

Cuestiones relacionadas