¿Qué significa " 2>&1 "?
Para combinar stderr
y stdout
en la stdout
secuencia, agregamos esto a un comando:
2>&1
por ejemplo, para ver los primeros errores de la compilación g++ main.cpp
:
g++ main.cpp 2>&1 | head
¿Qué 2>&1
significa, en detalle?
El descriptor de archivo 1 es la salida estándar ( stdout
).
El descriptor de archivo 2 es el error estándar ( stderr
).
Al principio, 2>1
puede parecer una buena forma de redirigir stderr
a stdout
. Sin embargo, en realidad se interpretará como "redireccionar stderr
a un archivo llamado 1
".
&
indica que lo que sigue y precede es un descriptor de archivo y no un nombre de archivo. Así, utilizamos 2>&1
. Considere >&
ser un operador de fusión de redireccionamiento.
Para redirigir la salida estándar a file.txt
:
echo test > file.txt
Esto equivale a:
echo test 1> file.txt
Para redirigir stderr a file.txt
:
echo test 2> file.txt
También lo >&
es la sintaxis para redirigir una secuencia a otro descriptor de archivo :
- 0 es entrada estándar
- 1 es salida estándar
- 2 es estándar
Para redirigir stdout a stderr:
echo test 1>&2 # equivalently, echo test >&2
Para redirigir stderr a stdout:
echo test 2>&1
Así, en 2>&1
:
2>
redirige stderr a un archivo (no especificado).&1
redirige stderr a stdout.
Algunos trucos sobre la redirección
Alguna particularidad de sintaxis sobre esto puede tener comportamientos importantes. Hay algunos pequeños ejemplos sobre redirecciones, STDERR
y STDOUT
ordenamiento de argumentos .
1 - ¿Sobrescribir o agregar?
El símbolo >
significa redirección .
>
significa enviar como un archivo completo y completo , sobrescribiendo el destino si existe (consultenoclobber
la función bash en el n.° 3 más adelante).>>
significa enviar además de agregarlo al destino si existe.
En cualquier caso, el archivo se crearía si no existieran.
2 - ¡La línea de comando del shell depende del orden!
Para probar esto, necesitamos un comando simple que envíe algo a ambas salidas :
$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan 7 11:49 /tmp
$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory
$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan 7 11:49 /tmp
(Esperando que no tenga un directorio llamado /tnt
, por supuesto;). Pues lo tenemos!!
Entonces, veamos:
$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory
$ ls -ld /tmp /tnt >/dev/null 2>&1
$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory
La última línea de comando vuelca STDERR
a la consola y parece no ser el comportamiento esperado... Pero...
Si desea realizar algún filtrado de publicaciones sobre salida estándar , salida de error o ambas:
$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan 7 12:02 /tmp --->
$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan 7 12:02 /tmp --->
$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'
$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
Observe que la última línea de comando en este párrafo es exactamente la misma que en el párrafo anterior, donde escribí parece no ser el comportamiento esperado (por lo tanto, este podría incluso ser un comportamiento esperado).
Bueno, hay algunos pequeños trucos sobre las redirecciones para realizar operaciones diferentes en ambas salidas :
$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2 2>&1 | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan 7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory
Nota : &9
el descriptor aparecería espontáneamente debido a ) 9>&2
.
Anexo: ¡nota! Con la nueva versión deintento( >4.0
) hay una nueva característica y una sintaxis más atractiva para hacer este tipo de cosas:
$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov 5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory
Y finalmente para un formato de salida en cascada:
$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
1 O: drwxrwxrwt 118 root root 196608 Jan 7 12:29 /tmp
2 E: ls: cannot access /tnt: No such file or directory
Anexo: ¡nota! La misma nueva sintaxis, en ambos sentidos:
$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
1 O: drwxrwxrwt 17 root root 28672 Nov 5 23:00 /tmp
2 E: ls: cannot access /tnt: No such file or directory
Donde STDOUT
pasa por un filtro específico, STDERR
a otro y finalmente ambas salidas fusionadas pasan por un tercer filtro de comando.
2b - Usar |&
en su lugar
La sintaxis command |& ...
podría usarse como alias para command 2>&1 | ...
. Se aplican las mismas reglas sobre el orden de la línea de comandos. Más detalles en ¿Cuál es el significado del operador |& en bash?
3 - Unas palabras sobre noclobber
opciones y >|
sintaxis
Se trata de sobrescribir :
Si bien set -o noclobber
le indica a bash que no sobrescriba ningún archivo existente, la >|
sintaxis le permite superar esta limitación:
$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)
$ date > $testfile ; cat $testfile
Mon Jan 7 13:18:15 CET 2013
$ date > $testfile ; cat $testfile
Mon Jan 7 13:18:19 CET 2013
$ date > $testfile ; cat $testfile
Mon Jan 7 13:18:21 CET 2013
El archivo se sobrescribe cada vez, bueno, ahora:
$ set -o noclobber
$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan 7 13:18:21 CET 2013
$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan 7 13:18:21 CET 2013
Pasar con >|
:
$ date >| $testfile ; cat $testfile
Mon Jan 7 13:18:58 CET 2013
$ date >| $testfile ; cat $testfile
Mon Jan 7 13:19:01 CET 2013
Desarmar esta opción y/o preguntar si ya está configurada.
$ set -o | grep noclobber
noclobber on
$ set +o noclobber
$ set -o | grep noclobber
noclobber off
$ date > $testfile ; cat $testfile
Mon Jan 7 13:24:27 CET 2013
$ rm $testfile
4 - Último truco y más...
Para redirigir ambas salidas de un comando determinado, vemos que la sintaxis correcta podría ser:
$ ls -ld /tmp /tnt >/dev/null 2>&1
para este caso especial , existe una sintaxis abreviada: &>
... o>&
$ ls -ld /tmp /tnt &>/dev/null
$ ls -ld /tmp /tnt >&/dev/null
Nota: si 2>&1
existe, 1>&2
también es una sintaxis correcta:
$ ls -ld /tmp /tnt 2>/dev/null 1>&2
4b- Ahora te dejaré pensar en:
$ ls -ld /tmp /tnt 2>&1 1>&2 | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb 9 11:08 /tmp/
$ ls -ld /tmp /tnt 1>&2 2>&1 | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb 9 11:08 /tmp/
4c- Si estás interesado en más información
Puedes leer el excelente manual presionando:
man -Len -Pless\ +/^REDIRECTION bash
en unintentoconsola ;-)