Descriptores de archivo y scripting de shell

32

Me está costando mucho entender cómo se usan los descriptores de archivos en los scripts de shell.

Sé lo básico como

exec 5 > /tmp/foo

Entonces fd 5 se adjunta a foo para escribir.

exec 6 < /tmp/bar

… para leer.

exec 5>&-

... cierre fd.

Ahora que hace esto?

#!/bin/bash

exec 5 > /tmp/foo 
exec 6 < /tmp/bar 

cat <&6 | while read a
do
     echo $a >&5
done

Según tengo entendido, &5cierra el fd, entonces, ¿cómo se redirige la salida correctamente después de cada llamada?

Esta es una copia de pasta de: Aquí

Afirma que usar esto sobre un simple echo $a > filelo haría mucho más rápido, sin embargo, no lo entiendo. Agradecería cualquier enlace a un tutorial decente. Yo google poderes parecen estar fallando.

Ricko M
fuente

Respuestas:

44

Primero, tenga en cuenta que la sintaxis para cerrar es 5>&-o 6<&-, dependiendo de si el descriptor de archivo se está leyendo para escribir o para leer. Parece que hay un error tipográfico o de formato en esa publicación de blog.

Aquí está el guión comentado.

exec 5>/tmp/foo       # open /tmp/foo for writing, on fd 5
exec 6</tmp/bar       # open /tmp/bar for reading, on fd 6
cat <&6 |             # call cat, with its standard input connected to
                      # what is currently fd 6, i.e., /tmp/bar
while read a; do      # 
  echo $a >&5         # write to fd 5, i.e., /tmp/foo
done                  # 

No hay cierre aquí. Debido a que todas las entradas y salidas van al mismo lugar en este simple ejemplo, no es necesario el uso de descriptores de archivo adicionales. Podrías escribir

cat </tmp/bar |
while read a; do
  echo $a
done >/tmp/foo

El uso de descriptores de archivo explícitos se vuelve útil cuando desea escribir en varios archivos a la vez. Por ejemplo, considere un script que genera datos en un archivo de salida de datos y registra datos en un archivo de registro y posiblemente también mensajes de error. Eso significa tres canales de salida: uno para datos, uno para registros y otro para errores. Como solo hay dos descriptores estándar para la salida, se necesita un tercero. Puede llamar execpara abrir los archivos de salida:

exec >data-file
exec 3>log-file
echo "first line of data"
echo "this is a log line" >&3

if something_bad_happens; then echo error message >&2; fi
exec >&-  # close the data output file
echo "output file closed" >&3

El comentario sobre la eficiencia aparece cuando tiene una redirección en un bucle, como esta (suponga que el archivo está vacío para empezar):

while …; do echo $a >>/tmp/bar; done

En cada iteración, el programa se abre /tmp/bar, busca el final del archivo, agrega algunos datos y cierra el archivo. Es más eficiente abrir el archivo de una vez por todas:

while …; do echo $a; done >/tmp/bar

Cuando se producen varias redirecciones en diferentes momentos, execresulta útil llamar para realizar redirecciones en lugar de envolver un bloque en una redirección.

exec >/tmp/bar
while …; do echo $a; done

Encontrará varios otros ejemplos de redireccionamiento al explorar la io-redirectionetiqueta en este sitio .

Gilles 'SO- deja de ser malvado'
fuente
1
Cualquiera de las sintaxis para cerrar el descriptor de archivo realmente hace lo mismo.
user1338062