bash - all - redirect stdout and stderr to file
Shell redireccionamiento i/o orden (4)
Estoy jugando con la redirección de shell I / O. Los comandos que he probado (en bash):
ls -al *.xyz 2>&1 1> files.lst
y
ls -al *.xyz 1> files.lst 2>&1
No hay ningún archivo *.xyz
en la carpeta actual.
Estos comandos me dan los diferentes resultados. El primer comando muestra un mensaje de error ls: *.xyz: No such file or directory
en la pantalla. Pero el segundo imprime este mensaje de error en el archivo. ¿Por qué el primer comando no pudo escribir una salida de error en el archivo?
El manual de Bash tiene un ejemplo claro (similar al suyo) para mostrar que el pedido es importante y también explica la diferencia. Aquí está la parte relevante extraída (énfasis mío):
Tenga en cuenta que el orden de redirecciones es significativo. Por ejemplo, el comando
ls> dirlist 2> & 1
dirige tanto la salida estándar (descriptor de archivo 1) como el error estándar (descriptor de archivo 2) al dirlist del archivo, mientras que el comando
ls 2> & 1> dirlist
dirige solo la salida estándar al archivo dirlist , porque el error estándar se hizo una copia de la salida estándar antes de que la salida estándar se redirigiera a dirlist .
Esta publicación lo explica desde el punto de vista POSIX.
Las confusiones ocurren debido a una diferencia clave. >
redirige no haciendo que el operando izquierdo ( stderr
) apunte al operando derecho ( stdout
) sino haciendo una copia del operando derecho y asignándola a la izquierda. Conceptualmente, cesión por copia y no por referencia.
Así que leer de izquierda a derecha, que es como se interpreta esto por Bash: ls > dirlist 2>&1
significa redireccionar stdout
al archivo dirlist
, seguido por el redireccionamiento de stderr
a cualquier stdout
actual (que ya es el archivo dirlist
). Sin embargo, ls 2>&1 > dirlist
redireccionaría stderr
a cualquier stdout
esté actualmente (que es la pantalla / terminal) y luego redireccionará stdout
a dirlist
.
Este error:
ls: *.xyz: No such file or directory
está siendo escrito en stderr
por ls
binario.
Sin embargo en este comando:
ls -al *.xyz 2>&1 1> files.lst
Primero está redirigiendo stderr
a stdout
que de forma predeterminada va a tty
(terminal)
Y luego está redireccionando stdout
a un archivo files.lst
, sin embargo, recuerde que stderr no se redirige a archivo ya que tiene stderr
a stdout
redirection antes de stdout
a file
redirection. Su stderr
todavía se escribe a tty
en este caso.
Sin embargo, en el segundo caso, cambia el orden de las redirecciones (primero stdout
a file
y luego stderr
a stdout
) y eso redirige correctamente stderr
a un file
que stdout
también está utilizando.
Las redirecciones son:
- Procesado de izquierda a derecha.
- interpretado iterativamente
- una redirección anterior puede afectar a una posterior :
- Si una redirección anterior ha redirigido una secuencia determinada (identificada por un número de descriptor de archivo, como
1
para stdout (el valor predeterminado) y2
para stderr), las redirecciones posteriores dirigidas a esa corriente se refieren a la versión ya redirigida.
- Si una redirección anterior ha redirigido una secuencia determinada (identificada por un número de descriptor de archivo, como
- pero no al revés , una redirección posterior no tiene efecto retroactivo en el objetivo de una redirección anterior:
- por ejemplo, si especifica el descriptor de archivo
1
como destino en una redirección anterior, lo que1
significa en ese momento está bloqueado, incluso si1
se redirige más adelante.
- por ejemplo, si especifica el descriptor de archivo
- una redirección anterior puede afectar a una posterior :
- Sin embargo, tenga en cuenta que la salida no se envía realmente hasta que todas las redirecciones están en su lugar, y que cualquier archivo de salida de redireccionamiento objetivo se crea o trunca antes de que comience la ejecución del comando (esta es la razón por la que no puede leer y redirigir la salida a el mismo archivo con un solo comando).
Aplicado al ejemplo de la pregunta:
>file 2>&1
:-
>file
primer>file
redirige stdout (descriptor de archivo1
, implícito sin prefijo>
con un número de descriptor de archivo) al archivo defile
salida -
2>&1
luego redirige stderr (2
) a la salida estándar ya redirigida (1
). - El efecto neto es que ambas secuencias originales terminan en el
file
.
-
2>&1 >file
:-
2>&1
primero redirige stderr a la salida estándar entonces original ; ya que el descriptor de archivos2
participa en ninguna otra redirección, la salida de stderr irá a cualquier stdout que se haya definido en ese punto , es decir, la stdout original , dado que esta es la primera redirección.- Técnicamente, el descriptor de archivo stdout original está duplicado , y ese duplicado es a lo que luego se refiere stderr, lo que explica por qué no se ve afectado por una redirección posterior de stdout.
-
>file
luego el>file
redirige el stdout original alfile
, pero eso ya no tiene efecto en el redireccionamiento ya bloqueado de stderr. - El efecto neto es que solo la salida enviada directamente a la salida
file
se captura en elfile
, mientras que la salida enviada a la salidafile
envía a la salida estándar (la original, sin redirigir).
-
Porque el orden sí importa. En el primer caso, primero redirigir stderr (2) a stdout (1). Luego redireccionas (1) a un archivo. Pero stderr (2) sigue apuntando a la salida estándar del shell que ejecuta el comando. En este caso, señalar (1) a un archivo no cambia el dispositivo de salida al que se dirige (2), por lo que aún va al terminal.
En el segundo caso, redirige stdout (1) a un archivo. Luego apunta stderr (2) al mismo lugar donde se señala 1, que es el archivo, por lo que el mensaje de error va al archivo.