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
1para stdout (el valor predeterminado) y2para 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
1como destino en una redirección anterior, lo que1significa en ese momento está bloqueado, incluso si1se 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:-
>fileprimer>fileredirige stdout (descriptor de archivo1, implícito sin prefijo>con un número de descriptor de archivo) al archivo defilesalida -
2>&1luego 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>&1primero redirige stderr a la salida estándar entonces original ; ya que el descriptor de archivos2participa 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.
-
>fileluego el>fileredirige 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
filese captura en elfile, mientras que la salida enviada a la salidafileenví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.