En el shell, ¿qué significa “2> & 1”?

En un shell Unix, si deseo combinar stderr y stdout en la stream stdout 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 syntax de este truco en particular.

¿Alguien puede romper esto y explicar carácter por personaje qué 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 ).

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 .

 echo test > afile.txt 

redirige 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 syntax 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.

Algunos trucos sobre la redirección

Alguna particularidad de syntax sobre esto puede tener comportamientos importantes. Hay algunas pequeñas muestras sobre las redirecciones, STDERR , STDOUT y el orden de los argumentos.

1 – ¿Sobrescribir o agregar?

Símbolo > redirección media.

  • > significa enviar como un archivo completo completado , sobrescribiendo el objective si existe (ver la función noclobber bash en # 3 más adelante).
  • >> significa enviar además de anexaría al objective si existiera.

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

2 – ¡La línea de comandos del shell depende de los pedidos!

Para probar esto, necesitamos un comando simple que envíe algo en ambos productos :

 $ 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 

La última línea de comando descarga STDERR a la consola, y parece que no es el comportamiento esperado … Pero …

Si desea hacer un 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 ---> 

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

Bueno, hay algunos pequeños trucos sobre las redirecciones, para hacer una operación diferente 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 descriptor ocurriría espontáneamente debido a ) 9>&2 .

Adición: ¡nota! Con la nueva versión de bash ( >4.0 ) hay una nueva característica y una syntax 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 syntax, 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 ambos productos fusionados pasan por un tercer filtro de comando.

3 – Una palabra sobre la opción noclobber y >| syntax

Eso es sobre sobrescribir :

Mientras set -o noclobber instruir a bash para que no sobrescriba ningún archivo existente, el >| la syntax 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 resultados desde un comando dado, vemos que una syntax correcta podría ser:

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

para este caso especial , hay una syntax de acceso directo: &> … o >&

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

Nota: si 2>&1 existen, 1>&2 es una syntax correcta:

 $ 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 -es/^/++/ ++/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 -es/^/++/ /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 obtener más información

Puede leer el manual fino presionando:

 man -Len -Pless\ +/^REDIRECTION bash 

en una consola bash 😉

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

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

2>&1 redirige a fd 2 a 1.

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

Puede ver /usr/include/unistd.h si los olvida:

 /* 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.

Encontré esta shiny 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:

Ingrese la descripción de la imagen aquí

Como puede ver, tanto stdout como stderr ahora apuntan al file . Entonces, todo lo escrito en stdout y stderr se escribe en el 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 al 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í:

Ingrese la descripción de la imagen aquí

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

Ingrese la descripción de la imagen aquí

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:

Ingrese la descripción de la imagen aquí

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í:

Ingrese la descripción de la imagen aquí

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:

Ingrese la descripción de la imagen aquí

Ahora Bash ve el segundo redireccionamiento, >file , y redirige stdout al archivo:

Ingrese la descripción de la imagen aquí

¿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

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

Puede redirigir cualquier identificador de salida a otro utilizando este método, pero a menudo se usa para canalizar flujos stdout y stderr en un solo flujo 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 este último no direccionará stderr a outfile2 – lo redirecciona a lo que stdout era cuando se encontró el argumento ( outfile1 ) y luego redirige stdout a outfile2 .

Esto permite algunos trucos bastante sofisticados.

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


2 : descriptor de archivo de salida ” error estándar “.

>& : Duplicar un operador de descriptor de archivo de salida (una variante del operador de redirección de salida > ). Dado [x]>&[y] , el descriptor de archivo denotado por x se convierte en una copia del descriptor de archivo de salida y .

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

La expresión 2>&1 copia el descriptor de archivo 1 en la ubicación 2 , por lo que cualquier salida escrita en 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 utilizado para identificar un archivo abierto con el propósito de acceso a archivos”.

Salida / error estándar : consulte la siguiente nota en la sección Redirecció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 progtwigs 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.

Para responder a su pregunta: Toma cualquier salida de error (normalmente enviada a stderr) y la escribe en salida estándar (stdout).

Esto es útil con, por ejemplo, “más” cuando necesita paginación para todos los resultados. Algunos progtwigs como imprimir información de uso en stderr.

Para ayudarte a recordar

  • 1 = salida estándar (donde los progtwigs imprimen salida normal)
  • 2 = error estándar (donde los progtwigs imprimen errores)

“2> & 1” simplemente señala todo enviado a stderr, a stdout en su lugar.

También recomiendo leer esta publicación sobre redireccionamiento de errores donde se trata este tema con todo detalle.

2 es el error estándar de la consola.

1 es la salida estándar de la consola.

Este es el Unix estándar, y Windows también sigue el POSIX.

Por ejemplo, cuando corres

 perl test.pl 2>&1 

el error estándar se redirige a la salida estándar, por lo que puede ver ambas salidas juntas:

 perl test.pl > debug.log 2>&1 

Después de la ejecución, puede ver todos los resultados, incluidos los errores, en debug.log.

 perl test.pl 1>out.log 2>err.log 

Luego, la salida estándar va a out.log, y el error estándar a err.log.

Te sugiero que trates de entender esto.

Desde el punto de vista de un progtwigdor, significa precisamente esto:

 dup2(1, 2); 

Ver la página man .

Entender que 2>&1 es una copia también explica por qué …

 command >file 2>&1 

… no es lo mismo que …

 command 2>&1 >file 

El primero enviará ambas secuencias al file , mientras que el segundo enviará los errores a la salida file y la salida ordinaria al file .

Gente, siempre recuerda la pista de paxdiablo sobre la ubicación actual del objective de redirección … Es importante.

Mi mnemónico personal para el operador 2>&1 es este:

  • Piense en & queriendo decir 'and' o 'add' (el personaje es un ampers – ¿ y no es así?)
  • Entonces se convierte en: ‘redirigir 2 (stderr) a donde 1 (stdout) ya / actualmente y agregar ambas streams’ .

El mismo mnemónico funciona para la otra redirección de uso frecuente también, 1>&2 :

  • Piensa en & significa and o add … (¿entiendes la idea del símbolo, sí?)
  • Entonces se convierte en: ‘redirigir 1 (stdout) a donde 2 (stderr) ya / actualmente y agregar ambas streams’ .

Y recuerde siempre: debe leer cadenas de redirecciones ‘desde el final’, de derecha a izquierda ( no de izquierda a derecha).

Siempre que /foo no exista en su sistema y /tmp sí …

 $ ls -l /tmp /foo 

imprimirá el contenido de /tmp e imprimirá un mensaje de error para /foo

 $ ls -l /tmp /foo > /dev/null 

enviará el contenido de /tmp a /dev/null e imprimirá un mensaje de error para /foo

 $ ls -l /tmp /foo 1> /dev/null 

hará exactamente lo mismo (tenga en cuenta el 1 )

 $ ls -l /tmp /foo 2> /dev/null 

imprimirá el contenido de /tmp y enviará el mensaje de error a /dev/null

 $ ls -l /tmp /foo 1> /dev/null 2> /dev/null 

enviará tanto el listado como el mensaje de error a /dev/null

 $ ls -l /tmp /foo > /dev/null 2> &1 

es taquigrafía

Esto es como pasar el error al stdout o al terminal.

Es decir, cmd no es un comando:

 $cmd 2>filename cat filename command not found 

El error se envía al archivo de esta manera:

 2>&1 

El error estándar se envía a la terminal.

Redirigir entrada

El redireccionamiento de la entrada hace que el archivo cuyo nombre resulta de la expansión de la palabra se abra para leer en el descriptor de archivo n, o la entrada estándar (descriptor de archivo 0) si no se especifica n.

El formato general para la entrada de redireccionamiento es:

 [n] 

Redirigir la salida

La redirección de la salida hace que el archivo cuyo nombre resulta de la expansión de la palabra se abra para escribir en el descriptor de archivo n, o la salida estándar (descriptor de archivo 1) si n no está especificado. Si el archivo no existe, se crea; si existe, se trunca a tamaño cero.

El formato general para redirigir salida es:

 [n]>word 

Desplazamientos de descriptores de archivos

El operador de redirección,

 [n]<&digit- 

mueve el dígito del descriptor de archivo al descriptor de archivo n, o la entrada estándar (descriptor de archivo 0) si n no está especificado. el dígito se cierra después de duplicarse en n.

Del mismo modo, el operador de redirección

 [n]>&digit- 

mueve el dígito del descriptor de archivo al descriptor de archivo n, o la salida estándar (descriptor de archivo 1) si n no se especifica.

Árbitro:

 man bash 

Escribe /^REDIRECT para localizar la sección de redirection y aprender más ...

Una versión en línea está aquí: 3.6 Redirecciones

PD:

Muchas veces, el man era la herramienta poderosa para aprender Linux.

0 para entrada, 1 para stdout y 2 para stderr.

Un consejo : somecmd >1.txt 2>&1 es correcto, mientras que somecmd 2>&1 >1.txt es totalmente incorrecto sin ningún efecto.