En un shell Unix, si quiero combinar stderr
y stdout
en el flujo stdout
para su posterior manipulación, puedo añadir lo siguiente al final de mi comando:
2>&1
Así, si quiero usar head
en la salida de g++
, puedo hacer algo como esto:
g++ lots_of_errors 2>&1 | head
para poder ver sólo los primeros errores.
Siempre tengo problemas para recordar esto, y constantemente tengo que ir a buscarlo, y es principalmente porque no entiendo completamente la sintaxis de este truco en particular.
¿Puede alguien desglosar esto y explicar carácter por carácter lo que significa 2>&1
?
El descriptor de archivo 1 es la salida estándar (stdout
);
El descriptor de archivo 2 es el error estándar (stderr
).
Esta es una forma de recordar esta construcción (aunque no es del todo precisa): al principio, 2>1
puede parecer una buena forma de redirigir stderr
a stdout
. Sin embargo, en realidad se interpretará como "redirigir stderr
a un fichero llamado 1
". La palabra &
indica que lo que sigue es un descriptor de archivo y no un nombre de archivo. Así que la construcción se convierte en: 2>&1
.
echo test > afile.txt
redirige stdout a afile.txt
. Esto es lo mismo que hacer
echo test 1> afile.txt
Para redirigir stderr, se hace:
echo test 2> afile.txt
>&
es la sintaxis para redirigir un flujo a otro descriptor de archivo - 0 es stdin, 1 es stdout, y 2 es stderr.
Puedes redirigir stdout a stderr haciendo:
echo test 1>&2 # or echo test >&2
O viceversa:
echo test 2>&1
Así que, en resumen... 2>
redirige stderr a un archivo (no especificado), añadiendo &1
redirige stderr a stdout.
Los números se refieren a los descriptores de archivo (fd).
stdin
.stderr
.2>&1
redirige fd 2 a 1.
Esto funciona para cualquier número de descriptores de archivo si el programa los utiliza.
Puedes mirar en /usr/include/unistd.h
si los olvidas:
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
Dicho esto, he escrito herramientas en C que utilizan descriptores de archivo no estándar para el registro personalizado, por lo que no lo ves a menos que lo redirijas a un archivo o algo así.