Pregunta

En un shell de Unix, si deseo 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

para que pueda ver solo los primeros errores.

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

¿Alguien puede dividir esto y explicar carácter por carácter lo que significa 2 > & amp; 1 ?

¿Fue útil?

Solución

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 " ;. & amp; indica que lo que sigue es un descriptor de archivo y no un nombre de archivo. Entonces la construcción se convierte en: 2 > & amp; 1 .

Otros consejos

echo test > afile.txt

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

echo test 1> afile.txt

Para redirigir stderr, debe hacer:

echo test 2> afile.txt

> & amp; 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), agregando & amp; 1 redirige stderr a stdout.

Algunos trucos sobre la redirección

Algunas particularidades de sintaxis sobre esto pueden tener comportamientos importantes. Hay algunas pequeñas muestras sobre redirecciones, STDERR , STDOUT y argumentos ordenación .

1 - ¿Sobrescribir o anexar?

Símbolo > significa redirección .

  • > significa enviar como un archivo completo completo , sobrescribiendo el objetivo si existe (vea la función bash de noclobber en # 3 más tarde).
  • > > significa que enviar además de se agregaría al objetivo si existe.

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

2 - ¡La línea de comando 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 volca STDERR en la consola, y parece que no es el comportamiento esperado ... Pero ...

Si desea realizar algunos filtros de publicación 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 la misma que en el párrafo anterior, donde escribí parece que no es el comportamiento esperado (por lo tanto, esto podría incluso ser un comportamiento esperado).

Bueno, hay algunos trucos sobre las redirecciones, para realizando diferentes operaciones 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 & amp; 9 ocurriría espontáneamente debido a ) 9 > & amp; 2 .

Anexo: nota! con la nueva versión de ( > 4.0 ) hay una nueva función 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

Anexo: nota! La misma sintaxis nueva, 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.

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

Se trata de sobrescribir :

Mientras set -o noclobber le indica a bash que no sobrescriba cualquier archivo existente, 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, 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 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

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

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

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

$ 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 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á interesado en más información

Puede leer el excelente manual presionando:

man -Len -Pless\ +/^REDIRECTION bash

en una ; -)

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

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

  

$ comando & amp; > archivo

Esta línea única utiliza el operador & amp; > para redirigir ambas secuencias de salida, stdout y stderr, del comando al archivo. Este es el acceso directo 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 haya redirigido ambas secuencias:

 Ingrese la descripción de la imagen aquí

Como puede ver, stdout y stderr ahora apuntan a file . Entonces, cualquier cosa escrita en stdout y stderr se escribe en file .

Hay varias formas de redirigir ambas transmisiones al mismo destino. Puede redirigir cada transmisión una tras otra:

  

$ command > archivo 2 > & amp; 1

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

Cuando Bash ve varias redirecciones, las procesa de izquierda a derecha. Veamos los pasos y veamos cómo sucede. 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 apunte al archivo:

 Ingrese la descripción de la imagen aquí

Next Bash ve la segunda redirección 2 > & amp; 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 se han redirigido a un archivo.

¡Pero ten cuidado aquí! Escritura

  

comando > archivo 2 > & amp; 1

no es lo mismo que escribir:

  

$ comando 2 > & amp; 1 > archivo

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

 Ingrese la descripción de la imagen aquí

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

 Ingrese la descripción de la imagen aquí

Ahora Bash ve la segunda redirección, > file , y redirige stdout a archivo:

 Ingrese la descripción de la imagen aquí

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

También tenga en cuenta que en Bash, escribir

  

$ comando & amp; > archivo

es exactamente lo mismo que:

  

$ comando > & amp; archivo

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

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

2 > & amp; 1 redirige fd 2 a 1.

Esto funciona para cualquier número de descriptores de archivos si el programa los usa.

Puede mirar /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, he escrito herramientas de C que usan descriptores de archivo no estándar para el registro personalizado para que no lo vea a menos que lo redirija a un archivo o algo así.

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 han sido descuidados por las otras respuestas.

Puede redirigir cualquier manejador de salida a otro utilizando este método, pero se usa con mayor frecuencia para canalizar stdout y stderr 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 el último no dirigirá stderr a outfile2 - lo redirige a lo que era stdout cuando se encontró el argumento ( outfile1 ) y luego redirige stdout a outfile2 .

Esto permite algunos trucos bastante sofisticados.

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


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

> & amp; : Duplicar un operador Descriptor de archivo de salida (una variante de Redirección de salida operador > ). Dado [x] > & amp; [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 expresión 2 > & amp; 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 originalmente descrito por 1 (" salida estándar ").


Explicación adicional:

Descriptor de archivos : " Un entero único, no negativo, por proceso utilizado para identificar un archivo abierto con el fin de acceder a él. "

Salida / error estándar : Consulte la siguiente nota en el Sección de redireccionamiento de la documentación del shell:

  

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

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 al POSIX.

Por ejemplo, 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 toda la salida, incluidos los errores, en el debug.log.

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

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

Te sugiero que trates de entender esto.

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

Esto es útil con, por ejemplo, 'más' cuando necesita paginación para toda la salida. Algunos programas les gusta imprimir información de uso en stderr.

Para ayudarlo a recordar

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

" 2 > & amp; 1 " simplemente señala todo lo enviado a stderr, a stdout en su lugar.

También recomiendo leer esta publicación en la redirección de error donde esto el tema está cubierto con todo detalle.

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

dup2(1, 2);

Consulte la página del manual .

Comprender que 2 > & amp; 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 a archivo , mientras que el segundo enviará errores a stdout , y la salida ordinaria a archivo .

Gente, recuerde siempre la sugerencia de paxdiablo sobre la ubicación actual del objetivo de redireccionamiento ... Es importante.

Mi nemotécnica personal para el operador 2 > & amp; 1 es esta:

  • Piense que & amp; significa 'y' o 'add' (el personaje es un ampers - y , ¿no es así?)
  • Entonces se convierte en: 'redirige 2 (stderr) a donde 1 (stdout) ya está / actualmente y agrega ambos transmisiones '.

La misma mnemónica funciona también para la otra redirección utilizada con frecuencia, 1 > & amp; 2 :

  • Piense en & amp; que significa y o add ... (tiene la idea sobre el signo y, ¿sí?)
  • Entonces se convierte en: 'redirige 1 (stdout) a donde 2 (stderr) ya está / actualmente y agrega ambos transmisiones '.

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

Siempre que / foo no exista en su sistema y / tmp sí & # 8230;

$ 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

Se envía un error estándar al terminal.

  

Redireccionando entrada

     

La redirección de entrada provoca el archivo cuyo nombre   resulta de la expansión de la palabra que se abrirá para leer en el archivo   descriptor n, o la entrada estándar (descriptor de archivo 0) si n es   no especificado.

     

El formato general para redirigir la entrada es:

[n]<word
     

Salida de redireccionamiento

     

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

     

El formato general para redirigir la salida es:

[n]>word
     

Descriptores de archivos en movimiento

     

El operador de redireccionamiento,

[n]<&digit-
     

mueve el dígito del descriptor de archivo al descriptor de archivo n, o el   entrada estándar (descriptor de archivo 0) si no se especifica n.   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 el   salida estándar (descriptor de archivo 1) si no se especifica n.

Ref:

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

PS:

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

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

Un consejo : somecmd > 1.txt 2 > & amp; 1 es correcto, mientras que somecmd 2 > & amp; 1 > 1.txt es totalmente incorrecto sin efecto!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top