Al utilizar nohup para poner un comando a ejecutar en segundo plano algunos de los contenidos aparecen en la terminal.
cp: error reading ‘/mnt/tt/file.txt’: Input/output error
cp: failed to extend ‘/mnt/tt/file.txt’: Input/output error
Quiero guardar ese contenido en un archivo.
Hay dos flujos de salida principales en Linux (y otros sistemas operativos), la salida estándar (stdout) y el error estándar (stderr). Los mensajes de error, como los que muestra, se imprimen en el error estándar. El operador de redirección clásico (comando > archivo
) sólo redirige la salida estándar, por lo que el error estándar se sigue mostrando en el terminal. Para redirigir stderr también, tienes algunas opciones:
Redirigir stdout a un archivo y stderr a otro archivo:
command > out 2>error
Redirigir stdout a un archivo (>out
), y luego redirigir stderr a stdout (2>&1
):
command >out 2>&1
Redirigir ambos a un archivo (esto no es soportado por todos los shells, bash
y zsh
lo soportan, por ejemplo, pero sh
y ksh
no):
command &> out
Para más información sobre los distintos operadores de control y redirección, consulte aquí.
Lo primero que hay que tener en cuenta es que hay un par de maneras dependiendo de su propósito y del shell, por lo tanto esto requiere una ligera comprensión de múltiples aspectos. Además, ciertos comandos como time
y strace
escriben la salida a stderr por defecto, y pueden o no proporcionar un método de redirección específico para ese comando
La teoría básica detrás de la redirección es que un proceso generado por el shell (asumiendo que es un comando externo y no incorporado al shell) es creado a través de las llamadas al sistema fork()
y execve()
, y antes de que esto ocurra otra llamada al sistema dup2()
realiza las redirecciones necesarias antes de que ocurra execve()
. En ese sentido, las redirecciones se heredan del shell padre. El m&>n
y m>n.txt
informan al shell sobre cómo realizar la llamada al sistema open()
y dup2()
(ver también Cómo funciona la redirección de entrada, Cuál es la diferencia entre redirección y tubería, y Qué significa exactamente & en la redirección de salida )
La más típica, es a través de 2>
en shells tipo Bourne, como dash
(que está enlazado simbólicamente a /bin/sh
) y bash
; el primero es el shell por defecto y compatible con POSIX y el otro es el que la mayoría de los usuarios utilizan para la sesión interactiva. Difieren en sintaxis y características, pero por suerte para nosotros la redirección del flujo de errores funciona igual (excepto el &>
no estándar). En el caso de csh y sus derivados, la redirección stderr no funciona del todo allí.
Volvamos a la parte 2>
. Dos cosas clave a notar: >
significa operador de redirección, donde abrimos un archivo y el entero 2
representa el descriptor de archivo stderr; de hecho esto es exactamente como el estándar POSIX para el lenguaje shell define la redirección en sección 2.7:
[n]redir-op word
Para la redirección simple >
, el entero 1
está implícito para stdout
, es decir, echo Hello World > /dev/null
es simplemente lo mismo que echo Hello World 1>/dev/null
. Tenga en cuenta que el operador de número entero o de redirección no puede ser entrecomillado, de lo contrario el shell no lo reconoce como tal, y en su lugar lo trata como una cadena literal de texto. En cuanto al espaciado, es importante que el entero esté al lado del operador de redirección, pero el archivo puede estar al lado del operador de redirección o no, es decir, comando 2>/dev/null
y comando 2> /dev/null
funcionarán bien.
La sintaxis algo simplificada para el típico comando en el shell sería
command [arg1] [arg2] 2> /dev/null
El truco aquí es que la redirección puede aparecer en cualquier lugar. Es decir, tanto 2> comando [arg1]
como comando 2> [arg1]
son válidos. Tenga en cuenta que para el shell bash
, existe &>
una forma de redirigir los flujos stdout y stderr al mismo tiempo, pero de nuevo - es específico de bash y si usted se esfuerza por la portabilidad de los scripts, puede que no funcione. Ver también Wiki de Ubuntu y Cuál es la diferencia entre &> y 2>&1.
Nota: El operador de redirección >> *trunca* un fichero y lo sobrescribe, si el fichero existe. El operador de redirección
>>puede utilizarse para añadir
>a un fichero. Si te das cuenta,
>está pensado para un solo comando. Para los scripts, podemos redirigir el flujo stderr de todo el script desde fuera como en
myscript.sh 2> /dev/null` o podemos hacer uso de exec built-in. El exec built-in tiene el poder de redirigir el flujo para toda la sesión del shell, por así decirlo, ya sea de forma interactiva o a través de un script. Algo así como
#!/bin/sh
exec 2> ./my_log_file.txt
stat /etc/non_existing_file
En este ejemplo, el archivo de registro debería mostrar stat: cannot stat '/etc/non_existing_file': No such file or directory
.
Otra forma es a través de las funciones. Como kopciuszek señaló en su respuesta, podemos escribir la declaración de la función con la redirección ya adjunta, es decir
some_function(){
command1
command2
} 2> my_log_file.txt
Comandos como time
y strace
escriben su salida a stderr por defecto. En el caso del comando time
, la única alternativa viable es redirigir la salida de todo el comando, es decir
time echo foo 2>&1 > file.txt
alternativamente, se puede redirigir la lista sincrónica o el subshell si se quiere separar la salida ( como se muestra en post relacionado ):
{ time sleep 1 2> sleep.stderr ; } 2> time.txt
Otros comandos, como strace
o dialog
proporcionan medios para redirigir stderr. strace
tiene la opción - <filename.txt>
que permite especificar el nombre de archivo donde se debe escribir la salida. También hay una opción para escribir un archivo de texto para cada subproceso que vea strace
. El comando dialog
escribe el texto de la interfaz de usuario en stdout pero la salida en stderr, así que para guardar su salida en una variable ( porque var=$(...)
y los pipelines sólo reciben stderr ) necesitamos intercambiar los descriptores de archivo
result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
pero adicionalmente, existe la bandera --output-fd
, que también podemos utilizar. También existe el método de las tuberías con nombre. Recomiendo leer el post enlazado sobre el comando dialog
para una descripción completa de lo que ocurre.