Pregunta En el shell, ¿qué significa "2> & 1"?


En un shell Unix, si quiero combinar stderr y stdout en el stdout transmisión para una mayor manipulación, puedo agregar lo siguiente al final de mi comando:

2>&1

Entonces, si quiero usar head en el resultado de g++, Puedo hacer algo como esto:

g++ lots_of_errors 2>&1 | head

entonces solo puedo ver 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.

¿Alguien puede romper esto y explicar carácter por personaje qué 2>&1  ¿medio?


1734
2018-05-03 22:57


origen


Respuestas:


El descriptor de archivo 1 es el resultado estándar (stdout)
El descriptor de archivo 2 es el error estándar (stderr)

Aquí hay una forma de recordar este constructo (aunque no es del todo exacto): al principio, 2>1 puede parecer una buena manera de redirigir stderr a stdout. Sin embargo, en realidad se interpretará como "redirigir" stderr a un archivo llamado 1". & indica que lo que sigue es un descriptor de archivo y no un nombre de archivo. Entonces la construcción se convierte en: 2>&1.


1942
2018-05-03 23:04



echo test > afile.txt

redirige a stdout a afile.txt. Esto es lo mismo que hacer

echo test 1> afile.txt

Para redirigir stderr, haces:

echo test 2> afile.txt

>& es la sintaxis para redirigir una secuencia a otro descriptor de archivo - 0 es stdin, 1 es stdout y 2 es stderr.

Puede redirigir stdout a stderr haciendo:

echo test 1>&2 # or echo test >&2

O viceversa:

echo test 2>&1

Entonces, en resumen ... 2> redirige stderr a un archivo (no especificado), anexando &1 redirige stderr a stdout.


481
2018-05-03 22:59



Algunos trucos sobre la redirección

Alguna particularidad de sintaxis sobre esto puede tener comportamientos importantes. Hay algunas pequeñas muestras sobre redirecciones, STDERR, STDOUTy argumentos ordenando.

1 - ¿Sobrescribir o agregar?

Símbolo > media redirección.

  • > media enviar a como un archivo completo completado, sobrescribiendo el objetivo si existe (ver noclobber función bash en # 3 luego).
  • >> media enviar además de se agregaría al objetivo si existiera.

En cualquier caso, el archivo se crearía si no existieran.

2 - El línea de comandos de shell es dependiente de la orden !!

Para probar esto, necesitamos un comando simple que enviará algo en 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 ;). ¡Bien, 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

Los últimos volcados de línea de comando STDERR a la consola, y parece que no es el comportamiento esperado ... Pero ...

Si quieres hacer algo filtrado posterior sobre un resultado, el otro o ambos:

$ 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 --->

Tenga en cuenta que la última línea de comando en este párrafo es exactamente la misma que en el párrafo anterior, donde escribí parece que no es el comportamiento esperado (Entonces, esto podría ser un comportamiento esperado).

Bueno, hay un pequeño truco sobre las redirecciones, para haciendo diferente operación 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

No un: &9descriptor ocurriría espontáneamente debido a ) 9>&2.

Adición: ¡nota! Con la nueva versión de  (>4.0) hay una nueva característica y una sintaxis más sexy 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

Adición: ¡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

Dónde STDOUT ir a través de un filtro específico, STDERR a otro y finalmente ambos productos fusionados pasan por un tercer filtro de comando.

3 - Una palabra sobre noclobber opción y >| sintaxis

Eso es todo sobrescribir:

Mientras set -o noclobber instruir a bash a no sobrescribir cualquier archivo existente, el >| la sintaxis le permite pasar por 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, ahora bien:

$ 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

Desactivar esta opción y / o preguntar si ya está configurado.

$ 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 ambos salida de un comando dado, vemos que una sintaxis correcta podría ser:

$ ls -ld /tmp /tnt >/dev/null 2>&1

para esto especial caso, hay una sintaxis de acceso directo: &> ... o >&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

Nota: si 2>&1 existe, 1>&2 es una sintaxis correcta también:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b- Ahora, te dejaré pensar acerca de:

$ 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

Puede leer el manual fino presionando:

man -Len -Pless\ +/^REDIRECTION bash

en un  consola ;-)


256
2018-04-29 16:33



Los números se refieren a los descriptores de archivos (fd).

  • Zero es stdin 
  • Uno es stdout 
  • Dos es stderr

2>&1 redirects fd 2 a 1.

Esto funciona para cualquier cantidad de descriptores de archivos si el programa los usa.

Puedes mirar /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, escribí herramientas C que usan descriptores de archivos no estándar para el registro personalizado, por lo que no lo verá a menos que lo redirija a un archivo o algo.


67
2018-05-03 22:58



Esa construcción envía la corriente de error estándar (stderr) al corriente ubicación de salida estándar (stdout) - este problema de moneda parece haber sido descuidado por las otras respuestas.

Puede redirigir cualquier manejador de salida a otro utilizando este método, pero se usa con más frecuencia para canalizar stdout y stderr fluye en una sola secuencia para su procesamiento.

Algunos ejemplos son:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

Tenga en cuenta que ese último no directo stderr a outfile2 - lo redirige a lo que stdout fue cuando se encontró el argumento (outfile1) y entonces redirige stdout a outfile2.

Esto permite algunos trucos bastante sofisticados.


49
2018-05-03 23:54



Encontré esta brillante publicación en la redirección: Todo sobre las redirecciones

Redirige la salida estándar y el error estándar a un archivo

$ command &> file

Este one-liner utiliza el &> operador para redirigir ambos flujos de salida - stdout y stderr - de comando a archivo. Este es el atajo de Bash para redirigir rápidamente ambas transmisiones al mismo destino.

Así es como se ve la tabla de descriptores de archivos después de que Bash ha redirigido ambas secuencias:

Enter image description here

Como puede ver, stdout y stderr ahora apuntan a file. Entonces, todo lo escrito en stdout y stderr se escribe en file.

Hay varias formas de redirigir ambas transmisiones al mismo destino. Puede redirigir cada flujo uno tras otro:

$ comando> archivo 2> & 1

Esta es una forma mucho más común de redirigir ambas secuencias a un archivo. First stdout se redirige a un archivo, y luego stderr se duplica para que sea el mismo que stdout. Entonces, ambas secuencias terminan apuntando a file.

Cuando Bash ve varias redirecciones, las procesa de izquierda a derecha. Repasemos los pasos y veamos cómo sucede eso. Antes de ejecutar cualquier comando, la tabla de descriptores de archivos de Bash se ve así:

Enter image description here

Ahora Bash procesa el primer archivo de redirección>. Hemos visto esto antes y hace que stdout point file:

Enter image description here

Siguiente Bash ve la segunda redirección 2> y 1. No hemos visto esta redirección antes. Éste duplica el descriptor de archivo 2 para que sea una copia del descriptor de archivo 1 y obtenemos:

Enter image description here

Ambas transmisiones han sido redirigidas a un archivo.

Sin embargo, ten cuidado aquí! Escritura

comando> archivo 2> & 1

no es lo mismo que escribir:

$ command 2> & 1> archivo

¡El orden de los redireccionamientos importa en Bash! Este comando redirige solo el resultado estándar al archivo. El stderr aún se imprimirá en la terminal. Para entender por qué sucede eso, repasemos los pasos nuevamente. Entonces, antes de ejecutar el comando, la tabla de descriptores de archivos se ve así:

Enter image description here

Ahora Bash procesa las redirecciones de izquierda a derecha. Primero ve 2> y 1 por lo que duplica stderr a stdout. La tabla de descriptores de archivos se convierte en:

Enter image description here

Ahora Bash ve la segunda redirección, >filey redirige stdout al archivo:

Enter image description here

¿Ves lo que sucede aquí? Stdout ahora apunta a archivo, ¡pero el stderr aún apunta a la terminal! ¡Todo lo que se escribe en stderr se imprime en la pantalla! ¡Así que ten mucho, mucho cuidado con el orden de los redireccionamientos!

También tenga en cuenta que en Bash, escribir

$ command &> file

es exactamente lo mismo que:

$ comando> & archivo


47
2017-10-29 13:04



2>&1 es una construcción de shell POSIX. Aquí hay un desglose, token por token:


2: "Error estándar"descriptor de archivo de salida.

>&: Duplicar un descriptor de archivo de salida operador (una variante de Redirección de salida operador >) Dado [x]>&[y], el descriptor de archivo denotado por x está hecho para ser una copia del descriptor de archivo de salida y.

1 "Salida estándar"descriptor de archivo de salida.

La expresion 2>&1 copia el descriptor de archivo 1 a la ubicación 2, por lo que cualquier salida escrita para 2 ("error estándar") en el entorno de ejecución va al mismo archivo descrito originalmente por 1 ("salida estándar").


Explicación adicional:

Descriptor de archivo: "Un entero único no negativo, por proceso, que se usa para identificar un archivo abierto con el fin de acceder a los archivos".

Salida / error estándar: Consulte la siguiente nota en Redirección sección de la documentación del shell:

Los archivos abiertos se representan con números decimales que comienzan con cero. El mayor valor posible es definido por la implementación; sin embargo, todas las implementaciones deben soportar al menos de 0 a 9, inclusive, para el uso de la aplicación. Estos números se llaman "descriptores de archivos". Los valores 0, 1 y 2 tienen un significado especial y usos convencionales y están implícitos en ciertas operaciones de redirección; se los conoce como entrada estándar, salida estándar y error estándar, respectivamente. Los programas generalmente toman su entrada de la entrada estándar y la salida de escritura en la salida estándar. Los mensajes de error generalmente se escriben en un error estándar. Los operadores de redirección pueden ir precedidos de uno o más dígitos (sin caracteres intermedios permitidos) para designar el número del descriptor del archivo.


13
2017-12-25 06:43