web-dev-qa-db-esp.com

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

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

2>&1

Entonces, si quiero usar head en la salida de g++, puedo hacer algo como esto:

g++ lots_of_errors 2>&1 | head

así que solo puedo ver los primeros errores.

Siempre tengo problemas para recordar esto y tengo que buscarlo constantemente, y es principalmente porque no entiendo completamente la sintaxis de este truco en particular.

¿Puede alguien romper esto y explicar carácter por carácter lo que significa 2>&1?

1980
Tristan Havelick

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 esta construcción (aunque no es del todo precisa): 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. Así que la construcción se convierte en: 2>&1.

2193
Ayman Hourieh
echo test > afile.txt

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

echo test 1> afile.txt

Para redireccionar stderr, usted 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 redireccionar stdout a stderr haciendo:

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

O viceversa:

echo test 2>&1

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

553
dbr

Algunos trucos sobre la redirección

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

1 - ¿Sobrescribir o anexar?

El símbolo > significa redirección.

  • > significa enviar como un archivo completo completo, sobrescribiendo el objetivo si existe (consulte noclobber característica bash en # 3 más adelante).
  • >> mean enviar además de se añadiría a target si existe.

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

2 - ¡La línea de comando de Shell depende del 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;). Bueno, 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 que no es el comportamiento esperado ... Pero ...

Si desea hacer algunos filtrado de publicaciones sobre una salida, la otra 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 igual que en el párrafo anterior, donde escribí parece que no es el comportamiento esperado (por lo tanto, esto podría ser un comportamiento esperado).

Bueno, hay algunos 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: el descriptor &9 ocurriría espontáneamente debido a ) 9>&2.

Addendum: nota! Con la nueva versión de bash (>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 de este tipo:

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

Addendum: 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 atraviesa un filtro específico, STDERR a otro y finalmente ambas salidas combinadas pasan por un tercer filtro de comando.

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

Eso es sobre sobrescribir :

Mientras que set -o noclobber da instrucciones a bash para no sobrescribir cualquier archivo existente, la sintaxis >| le permite pasar a través de 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

Pase a través de >|:

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

Desactivando esta opción y/o preguntando 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 redireccionar both output desde un comando dado, vemos que una sintaxis correcta podría ser:

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

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

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

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

Nota: si2>&1exist,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

Podrías leer el fino manual pulsando:

man -Len -Pless\ +/^REDIRECTION bash

en un bash console ;-)

291
F. Hauri

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

Redirige tanto la salida estándar como el error estándar a un archivo

$ comando &> archivo

Este one-liner usa el operador &> para redireccionar ambas secuencias de salida, stdout y stderr, desde el comando al archivo. Este es el acceso directo de Bash para redirigir rápidamente ambas transmisiones al mismo destino.

Aquí es cómo se ve la tabla del descriptor de archivos después de que Bash haya redirigido ambas secuencias:

 Enter image description here

Como puede ver, tanto stdout como stderr ahora apuntan a file. Así que cualquier cosa escrita en stdout y stderr se escribe en file.

Hay varias formas de redireccionar ambas transmisiones al mismo destino. Puedes redireccionar cada secuencia una tras otra:

$ comando> archivo 2> & 1

Esta es una forma mucho más común de redireccionar ambas secuencias a un archivo. La primera salida estándar se redirige al archivo, y luego stderr se duplica para que sea igual que la salida estándar. Así que ambas corrientes terminan apuntando a file.

Cuando Bash ve varias redirecciones, las procesa de izquierda a derecha. Vayamos a través de los pasos y veamos cómo sucede eso. Antes de ejecutar cualquier comando, la tabla del descriptor 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 sea un punto para archivar:

 Enter image description here

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

 Enter image description here

Ambas transmisiones han sido redirigidas a archivo.

Sin embargo ten cuidado aquí! Escritura

comando> archivo 2> & 1

no es lo mismo que escribir:

$ comando 2> & 1> archivo

El orden de redirecciones importa en Bash! Este comando redirige solo la salida estándar al archivo. El stderr todavía se imprimirá en el terminal. Para entender por qué sucede eso, repasemos los pasos nuevamente. Así que antes de ejecutar el comando, la tabla del descriptor de archivos se ve así:

 Enter image description here

Ahora Bash procesa redirecciones de izquierda a derecha. Primero ve 2> & 1, así 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, >file, y redirige la salida estándar al archivo:

 Enter image description here

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

También tenga en cuenta que en Bash, escribiendo

$ comando &> archivo

es exactamente lo mismo que:

$ comando> y archivo

79
Deen John

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

  • Cero es stdin
  • Uno es stdout
  • Dos es stderr

2>&1 redirige fd 2 a 1.

Esto funciona para cualquier número 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, he escrito herramientas en C que utilizan 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.

77
Colin Burnett

Esa construcción envía el flujo 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 redireccionar cualquier controlador de salida a otro utilizando este método, pero se usa con más frecuencia para canalizar las transmisiones stdout y stderr en una única transmisión 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 dirigirá stderr a outfile2 - lo redirecciona a lo que stdout era cuando se encontró el argumento (outfile1) y entonces redirige stdout a outfile2.

Esto permite algunos trucos bastante sofisticados.

54
paxdiablo

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


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

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

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

La expresión 2>&1 copia el descriptor de archivo 1 a 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 fin de acceder al archivo."

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

Los archivos abiertos están representados por números decimales que comienzan con cero. El valor más grande posible está definido por la implementación; sin embargo, todas las implementaciones deben admitir al menos 0 a 9, inclusive, para el uso de la aplicación. Estos números son llamados "descriptores de archivo". 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 les conoce como entrada estándar, salida estándar y error estándar, respectivamente. Los programas usualmente toman su entrada de la entrada estándar, y escriben la salida en la salida estándar. Los mensajes de error se escriben generalmente en error estándar. Los operadores de redirección pueden ir precedidos por uno o más dígitos (sin caracteres intermedios permitidos) para designar el número del descriptor de archivo.

17
wjordan

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.

P.ej. cuando corres

Perl test.pl 2>&1

el error estándar se redirige a la salida estándar, para que pueda 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 el 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.

17
Marcus Thornton

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

Esto es útil con, por ejemplo, 'más' cuando necesita paginación para todos los resultados. A algunos programas les gusta imprimir información de uso en stderr.

Para ayudarte a recordar

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

"2> & 1" simplemente apunta todo lo enviado a stderr, a stdout en su lugar.

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

16
Andrioid

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

dup2(1, 2);

Ver la página del manual .

Comprender 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á ambos flujos a file, mientras que el segundo enviará errores a stdout, y la salida ordinaria a file.

11
ams

Siempre que /foo no exista en su sistema y /tmp no existe ...

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

6
Matijs

Gente, recuerde siempre la pista de paxdiablo sobre la ubicación actual del destino de redirección ... Es es importante.

Mi mnemotecnia personal para el operador 2>&1 es esta:

  • Piensa que & significa 'and' o 'add' (el carácter es un ampers - y , ¿no es así?)
  • Entonces se convierte en: 'redirigir 2 (stderr) a donde 1 (stdout) ya está/actualmente y agregar ambas secuencias' .

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

  • Piensa que & significa and o add... (obtienes la idea sobre el signo, ¿sí?)
  • Entonces se convierte en: 'redirigir 1 (stdout) a donde 2 (stderr) ya está/actualmente y agregar ambas secuencias' .

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

6
Kurt Pfeifle

Esto es como pasar el error a la salida estándar 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 al terminal.

5
Kalanidhi

Redireccionando la entrada

La redirección de la entrada hace que el archivo cuyo nombre resulte de la expansión de Word se abra para leerlo en el descriptor de archivos n, o la entrada estándar (descriptor de archivos 0) si no se especifica n.

El formato general para redireccionar la entrada es:

[n]<Word

Salida de redireccionamiento

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

El formato general para redireccionar la salida es:

[n]>Word

Descriptores de archivos en movimiento

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 no se especifica n. dígito se cierra después de ser duplicado a 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 no se especifica n.

Árbitro:

man bash

Escriba /^REDIRECT para ubicarse en la sección redirection, y obtenga más información ...

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

PD:

Muchas veces, man fue la poderosa herramienta para aprender Linux.

4
yurenchen

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 efecto!

1
fzyzcjy