¿Qué significa " 2>&1 "?

Resuelto Tristan Havelick asked hace 15 años • 19 respuestas

Para combinar stderry stdouten la stdoutsecuencia, 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>&1significa, en detalle?

Tristan Havelick avatar May 04 '09 05:05 Tristan Havelick
Aceptado

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>1puede parecer una buena forma de redirigir stderra stdout. Sin embargo, en realidad se interpretará como "redireccionar stderra 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.

Ayman Hourieh avatar May 03 '2009 23:05 Ayman Hourieh

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).
  • &1redirige stderr a stdout.
dbr avatar May 03 '2009 22:05 dbr

Algunos trucos sobre la redirección

Alguna particularidad de sintaxis sobre esto puede tener comportamientos importantes. Hay algunos pequeños ejemplos sobre redirecciones, STDERRy STDOUTordenamiento 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 (consulte noclobberla 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 STDERRa 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 : &9el 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 STDOUTpasa por un filtro específico, STDERRa 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 noclobberopciones y >|sintaxis

Se trata de sobrescribir :

Si bien set -o noclobberle 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>&1existe, 1>&2tambié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 ;-)

F. Hauri - Give Up GitHub avatar Apr 29 '2013 16:04 F. Hauri - Give Up GitHub