and all bash shell stdout stderr io-redirection

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) y 2 para stderr), las redirecciones posteriores dirigidas a esa corriente se refieren a la versión ya redirigida.
    • 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 que 1 significa en ese momento está bloqueado, incluso si 1 se redirige más adelante.
  • 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 archivo 1 , implícito sin prefijo > con un número de descriptor de archivo) al archivo de file 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 archivos 2 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 al file , 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 el file , mientras que la salida enviada a la salida file 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.