Quiero evitar tener archivos temporales por ahí si mi programa falla.
UNIX es maravilloso porque puedes mantener un archivo abierto, incluso después de eliminarlo.
Entonces, si abre el archivo, elimínelo inmediatamente yentoncesrealice el procesamiento lento, hay muchas posibilidades de que incluso si su programa falla, el usuario no tendrá que limpiar el archivo.
En Shell a menudo veo algo similar a:
generate-the-file -o the-file
[...loads of other stuff that may use stdout or not...]
do_slow_processing < the-file
rm the-file
Pero si el programa falla antes, rm
el usuario tendrá que limpiarlo the-file
.
En Perl puedes hacer:
open(my $filehandle, "<", "the-file") || die;
unlink("the-file");
while(<$filehandle>) {
# Do slow processing stuff here
print;
}
close $filehandle;
Luego, el archivo se elimina tan pronto como se abre.
¿Existe una construcción similar en Shell?
Respuesta1
Esto se prueba en csh, tcsh, sh, ksh, zsh, bash, ash, sash:
echo foo > the-file
(rm the-file; cat) < the-file | do_slow_processing
do_other_stuff
o si lo prefieres:
(rm the-file; do_slow_processing) < the-file
do_other_stuff
Curiosamente, también funciona para fifos:
mkfifo the-fifo
(rm the-fifo; cat) < the-fifo | do_slow_processing &
echo foo > the-fifo
Esto se debe a que el lector queda bloqueado hasta que se escribe algo.
Respuesta2
generate-the-file > the-file
exec 5< the-file
rm the-file
...
do_slow_processing 0<&5
Notas:
- Necesita ejecutar exec sin ejecutable, por lo que afecta los descriptores del propio shell
- Sólo hasta fd 9 disponible
- Podrías usar /proc/self/fd/X si necesitas un nombre de archivo. Esta interfaz no es portátil entre versiones de UNIX (aunque probablemente funcione para usted).
- Intentar leer nuevamente el fd (por ejemplo, dos llamadas a
cat 0<&5
) fallará ya que se encuentra en EOF. Debería rebobinarlo o superarlo leyendo a través de/proc/self/fd/X
- En la mayoría de los casos, como se muestra arriba, puede prescindir de un archivo real y hacer una simple
generate-the-file | do_slow_processing
Actualizar:
El OP menciona que generate-the-file
es posible que no produzca su resultado en stdout. Hay algunos modismos para esto:
- Especifique un archivo de salida de
-
. Es habitual aceptar un nombre de archivo de salida de - para significar salida estándar. Esto esreconocido por POSIX.1-2017:Directriz 13: Para las utilidades que usan operandos para representar archivos que se abrirán para lectura o escritura, el operando '-' debe usarse para indicar solo entrada estándar (o salida estándar cuando está claro por el contexto que se está especificando un archivo de salida) o un archivo llamado -.
(para utilidades distintas de aquellas en las que lo definen explícitamente, está definido por la implementación, pero es muy probable que sea compatible con su generate-the-file
herramienta)
Utilice
/dev/stdout
o/proc/self/fd/1
. Depende del sistema operativo, ver¿Qué tan portátiles son /dev/stdin, /dev/stdout y /dev/stderr?Utilice la sustitución de procesos. bash le permitirá escribir
>(process substitution)
como un nombre de archivo. Por ejemplo:wget -O >(rot13 > pregunta.txt)https://unix.stackexchange.com/q/579535/70346
Esto no funcionará en todos los shells y requiere soporte del sistema operativo para los nombres de archivos fd.
Respuesta3
En el bash
shell, la forma de manejar la limpieza es mediante el uso del trap
comando EXIT (desde dentro del bash
shell, escriba help trap
):
trap 'rm temp-file' EXIT
Esta característica también existe en el dash
shell, frecuentemente asociada a un alias sh
en las distribuciones modernas de Linux.