Para guardar un descriptor de archivo, lo duplica en otro fd. Guardar una ruta al archivo correspondiente no es suficiente, necesitará guardar el modo de apertura, los indicadores de apertura, la posición actual dentro del archivo, etc. Y, por supuesto, para tuberías o tomas anónimas, eso no funcionaría, ya que no tienen camino. Lo que desea guardar es la descripción del archivo abierto al que se refiere el fd, y duplicar un fd en realidad está devolviendo un nuevo fd a la misma descripción del archivo abierto .
Para duplicar un descriptor de archivo en otro, con un shell tipo Bourne, la sintaxis es:
exec 3>&1
Arriba, fd 1 está duplicado en fd 3.
Cualquier cosa que fd 3 ya estuviera abierta antes estaría cerrada, pero tenga en cuenta que los fds 3 a 9 (generalmente más, hasta 99 con yash
) están reservados para ese propósito (y no tienen un significado especial contrario a 0, 1 o 2), el Shell sabe que no debe usarlos para su propio negocio interno. La única razón por la que fd 3 habría estado abierto de antemano es porque lo hizo en el script 1 , o la persona que llamó lo filtró.
Luego, puede cambiar stdout a otra cosa:
exec > /dev/null
Y más tarde, para restaurar stdout:
exec >&3 3>&-
( 3>&-
para cerrar el descriptor de archivo que ya no necesitamos).
Ahora, el problema con eso es que, excepto en ksh, cada comando que ejecute después exec 3>&1
heredará ese fd 3. Esa es una fuga de fd. Generalmente no es un gran problema, pero eso puede causar problemas.
ksh
establece el indicador close-on-exec en esos fds (para fds mayores de 2), pero no otros shells y otros shells no tienen forma de establecer ese indicador manualmente.
La solución para otro shell es cerrar el fd 3 para cada comando, como:
exec 3>&-
exec > file.log
ls 3>&-
uname 3>&-
exec >&3 3>&-
Incómodo. Aquí, la mejor manera sería no usar exec
nada, sino redirigir los grupos de comandos:
{
ls
uname
} > file.log
Allí, es el shell el que se encarga de guardar stdout y restaurarlo después (y lo hace internamente duplicándolo en un fd (por encima de 9, por encima de 99 para yash
) con el conjunto de indicadores close-on-exec ).
Nota 1
Ahora, la administración de esos fds 3 a 9 puede ser engorrosa y problemática si los usa extensamente o en funciones, especialmente si su script usa algún código de terceros que a su vez puede usar esos fds.
Algunas conchas ( zsh
, bash
, ksh93
, todo ello sumado la característica ( sugerido por Oliver Kiddle dezsh
) alrededor del mismo tiempo en 2005 después de haber sido discutido entre sus desarrolladores) tiene una sintaxis alternativa para asignar la primera fd libre por encima de 10 en vez que ayuda en este caso:
myfunction() {
local fd
exec {fd}>&1
# stdout was duplicated onto a new fd above 10, whose actual value
# is stored in the fd variable
...
# it should even be safe to re-enter the function here
...
exec >&"$fd" {fd}>&-
}