En el shell, ¿qué significa "2> & 1"?
En un shell Unix, si quiero combinar stderr
y stdout
en el flujo stdout
para una mayor manipulación, puedo añadir 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 constantemente tengo que ir a buscarlo, y es principalmente porque no entiendo completamente la sintaxis de este particular truco.
¿Puede alguien romper esto y explicar carácter por carácter lo que 2>&1
significa?
15 answers
El descriptor de fichero 1 es la salida estándar (stdout
).
El descriptor de archivo 2 es el error estándar (stderr
).
Aquí hay una manera 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 "redireccionar 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
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-09 20:18:47
echo test > afile.txt
Redirige stdout a afile.txt
. Esto es lo mismo que hacer
echo test 1> afile.txt
Para redirigir stderr, lo haces:
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.
Puede redirigir stdout a stderr haciendo:
echo test 1>&2 # or echo test >&2
O viceversa:
echo test 2>&1
Así que, en resumen... 2>
redirige stderr a un archivo (no especificado), añadiendo &1
redirige stderr a stdout.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-04 20:36:11
Algunos trucos sobre la redirección
Alguna particularidad de sintaxis sobre esto puede tener comportamientos importantes. Hay algunas pequeñas muestras sobre las redirecciones, STDERR
, STDOUT
, y argumentos ordenando.
1-Sobrescribir o anexar?
Símbolo >
significa redirección.
-
>
mean send to as a whole completed file , overwriting target if exist (seenoclobber
bash feature at #3 tarde). -
>>
mean send in addition to would append to target if exist.
En cualquier caso, el archivo sería creado si no existen.
2-La línea de comandos 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 tengas un directorio llamado /tnt
, por supuesto ;). Bueno, lo tenemos!!
Así que, vamos a véase:
$ 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 comandos vuelca STDERR
a la consola, y parece que no es el comportamiento esperado... Pero...
Si quieres hacer algún post filtering 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 comandos 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, esto incluso podría ser un comportamiento esperado).
Bueno, hay un poco trucos sobre redirecciones, para haciendo 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
.
Anexo: 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 tal 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! Misma nueva sintaxis, en ambos formas:
$ 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
pasan por un filtro específico, STDERR
a otro y finalmente ambas salidas fusionadas pasan por un tercer filtro de comandos.
3-Una palabra sobre la opción noclobber
y la sintaxis >|
Se trata de sobrescribir :
Mientras que set -o noclobber
indica a bash que no sobrescriba ningún 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, bien 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 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
Desactivar esta opción y/o preguntar si ya está establecida.
$ 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 ambos salida 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 abreviada: &>
... o >&
$ ls -ld /tmp /tnt &>/dev/null
$ ls -ld /tmp /tnt >&/dev/null
Nota: si 2>&1
existen, 1>&2
es una sintaxis correcta también:
$ ls -ld /tmp /tnt 2>/dev/null 1>&2
4b-Ahora, te dejaré pensar en: {[45]]}
$ 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
$ 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/
Puedes leer el manual fino pulsando: {[43]]}
man -Len -Pless\ +/^REDIRECTION bash
En una consolabash ; -)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-04 20:41:51
Los números se refieren a los descriptores de fichero (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 archivo 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 de C que utilizan 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-06 01:25:12
Encontré este brillante post en redirección: Todo sobre redirecciones
Redirigir tanto la salida estándar como el error estándar a un archivo
Command comando & > archivo
Este one-liner utiliza el operador &>
para redirigir ambos flujos de salida - stdout y stderr - from al comando file. 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 archivo después de Bash ha redirigido ambas corrientes:
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 maneras de redirigir ambos flujos al mismo destino. Puedes redirigir cada flujo uno tras otro:
Command comando > archivo 2> & 1
Esta es una forma mucho más común de redirigir ambas secuencias a un archivo. Primera salida estándar se redirige a archivo, y luego stderr se duplica para ser el mismo que stdout. Así que ambas corrientes terminan apuntando a file
.
Cuando Bash ve varias redirecciones, las procesa de izquierda a derecha. Repasemos los pasos y veamos cómo sucede. Antes de ejecutar cualquier comando, la tabla de descriptores de archivo de Bash se ve así:
Ahora Bash procesa la primera redirección >archivo. Hemos visto esto antes y hace que stdout apunte a archivo:
Siguiente Bash ve la segunda redirección 2>&1. No hemos visto esta redirección antes. Este duplica el descriptor de archivo 2 para ser una copia del descriptor de archivo 1 y obtenemos:
Ambas secuencias han sido redirigidas a file.
Sin embargo, tenga cuidado aquí! Escritura
Comando > archivo 2> & 1
No Es lo mismo que escribir:
Command comando 2> & 1 > archivo
El orden de redirecciones 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 de nuevo. Así que antes de ejecutar el comando, la tabla descriptor de archivo se ve así:
Ahora Bash procesa redirecciones de izquierda a derecha. Primero ve 2> & 1 por lo que duplica stderr a stdout. La tabla descriptor de archivo se convierte en:
Ahora Bash ve la segunda redirección, >file
, y redirige stdout a file:
¿Ves lo que sucede aquí? Stdout ahora apunta al archivo, pero el stderr todavía apunta a la terminal! Todo lo que se escribe en stderr todavía se imprime en la pantalla! Así que ser muy, muy cuidadoso con el orden de redirecciones!
También tenga en cuenta que en Bash, escribiendo
Command comando &>archivo
Es exactamente lo mismo que:
Command orden > & archivo
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-05 03:43:35
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 redirigir cualquier controlador de salida a otro utilizando este método, pero se usa con mayor frecuencia 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 dirigirá stderr
a outfile2
- lo redirige a lo que stdout
era cuando se encontró el argumento (outfile1
) y luego redirige stdout
a outfile2
.
Esto permite algunos trucos bastante sofisticados.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-26 08:39:06
2>&1
es una construcción POSIX shell. 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 operator >
). Dado [x]>&[y]
, el descriptor de fichero denotado por x
se hace para ser una copia del descriptor de fichero de salida y
.
1
"Salida estándar" archivo de salida descriptor.
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 por proceso, no negativo utilizado para identificar un archivo abierto con el propósito de acceder al archivo."
Salida estándar / error: Refiérase a la siguiente nota en la sección Redirección 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 de 0 a 9, inclusive, para su uso por la aplicación. Estos números se llaman "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; son conocido como 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 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 de archivo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-25 06:43:43
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 toda la salida. 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 este post sobre la redirección de errores donde este tema se cubre con todo detalle.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-03 23:24:58
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 se ejecuta
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 toda la salida, incluidos los errores, en la depuración.registro.
perl test.pl 1>out.log 2>err.log
Entonces la salida estándar va a salir.log, y error estándar para errar.registro.
I sugiero que trates de entender esto.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-05 03:14:53
Desde el punto de vista de un programador, significa precisamente esto:
dup2(1, 2);
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á ambos flujos a file
, mientras que el segundo enviará los errores a stdout
, y la salida ordinaria a file
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-03 10:20:34
Gente, siempre recuerden la sugerencia de paxdiablo sobre la ubicación actual del destino de redirección... es importante.
Mi mnemotécnica personal para el operador 2>&1
es esta:
- Piense en
&
como'and'
o'add'
(el carácter es un amperios-y, ¿no lo es?) - Así que se convierte en: ' redirigir
2
(stderr) a donde1
(stdout) ya/actualmente está y agregar ambos streams ' .
El mismo mnemotécnico funciona también para la otra redirección de uso frecuente, 1>&2
:
- Piensa en
&
que significaand
oadd
... (usted consigue la idea sobre el ampersand, sí?) - Así que se convierte en: 'redirigir
1
(stdout) a donde2
(stderr) ya/actualmente está y agregar ambos flujos'.
Y recuerda siempre: tienes que leer cadenas de redirecciones 'desde el final', de derecha a izquierda (no de izquierda a derecha).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-01 10:47:27
Siempre que /foo
no exista en su sistema y /tmp
no exist
$ 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 la 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 abreviatura
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-01 20:58:04
Esto es como pasar el error al stdout o al terminal.
Es decir, cmd
no es una orden:
$cmd 2>filename
cat filename
command not found
El error se envía al archivo de la siguiente manera:
2>&1
Se envía un error estándar al terminal.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-05 03:17:17
Redireccionando la entrada
La redirección de entrada causa el archivo cuyo nombre resultados de la expansión de word que se abrirá para su lectura en el archivo descriptor n, o la entrada estándar (descriptor de fichero 0) si n es no especificado.
El formato general para redirigir la entrada es:
[n]<word
Redirigiendo la salida
La redirección de la salida hace que el archivo cuyo nombre resulta de la expansión de la palabra que se abrirá para escribir en file descriptor n, o la salida estándar (descriptor de fichero 1) si n no se especifica. Si el archivo no existe, se crea; si existe se trunca a tamaño cero.
El formato general para redirigir la salida es:
[n]>word
Mover Descriptores de archivo
El operador de redirección,
[n]<&digit-
Mueve el dígito del descriptor de fichero al descriptor de fichero n, o entrada estándar (descriptor de archivo 0) si no se especifica n. el dígito está cerrado después de ser duplicado a n.
Del mismo modo, el operador de redirección
[n]>&digit-
Mueve el dígito del descriptor de fichero al descriptor de fichero n, o salida estándar (descriptor de fichero 1) si no se especifica n.
Ref:
man bash
Escriba /^REDIRECT
para localizar la sección redirection
y obtener más información...
Una versión en línea está aquí: 3.6 Redirecciones
PS:
Muchas veces, man
fue la poderosa herramienta para aprender Linux.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-05 03:25:15
0 para input, 1 para stdout y 2 para stderr.
Un consejo :
{[0] } es correcto, mientras que somecmd 2>&1 >1.txt
es totalmente incorrecto sin ningún efecto!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-25 09:46:19