Cerrar todos los descriptores de archivo en bash


11

¿Hay alguna manera de cerrar todos los descriptores de archivos abiertos, sin tener una lista explícita de ellos de antemano?


44
Todos los cuales archivos descriptores? Cada proceso tiene algo abierto.
Warren Young

¿Qué son "todos los descriptores de archivos abiertos"? 0, 1 y 2? ¿O tienes muchos más? Si es así, ¿de dónde vinieron?
U. Windl

¿No se cierran automáticamente los descriptores de archivo cuando finaliza el script?
jarno

Respuestas:


14

Para responder literalmente, cerrar todos los descriptores de archivos abiertos para bash:

for fd in $(ls /proc/$$/fd); do
  eval "exec $fd>&-"
done

Sin embargo, esto realmente no es una buena idea, ya que cerrará los descriptores de archivo básicos que el shell necesita para entrada y salida. Si hace esto, ninguno de los programas que ejecute mostrará su salida en el terminal (a menos que escriban ttydirectamente en el dispositivo). Si el hecho de cerrar mis pruebas stdin( exec 0>&-) solo hace que salga un shell interactivo.

Lo que puede estar buscando hacer es cerrar todos los descriptores de archivos que no forman parte de la operación básica del shell. Estos son 0 para stdin, 1 para stdouty 2 para stderr. Además de esto, algunos shells también parecen tener otros descriptores de archivos abiertos de forma predeterminada. En bash, por ejemplo, tiene 255 (también para E / S de terminal) y en dash10, que apunta en /dev/ttylugar del dispositivo tty/ ptsdispositivo específico que está utilizando el terminal. Para cerrar todo, excepto 0, 1, 2 y 255 en bash:

for fd in $(ls /proc/$$/fd); do
  case "$fd" in
    0|1|2|255)
      ;;
    *)
      eval "exec $fd>&-"
      ;;
  esac
done

Tenga en cuenta también que evales necesario al redirigir el descriptor de archivo contenido en una variable, si no bashse expandirá la variable, pero considérelo parte del comando (en este caso, trataría execdel comando 0o del 1descriptor de archivo que esté intentando cerrar).

NOTA: También el uso de un glob en lugar de ls(por ejemplo /proc/$$/fd/*) parece abrir un descriptor de archivo adicional para el glob, por lo que lsparece la mejor solución aquí.

Actualizar

Para obtener más información sobre la portabilidad de /proc/$$/fd, consulte Portabilidad de enlaces de descriptor de archivo . Si /proc/$$/fdno está disponible, entonces sería una caída en el reemplazo para el $(ls /proc/$$/fd)uso lsof(si está disponible) $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-).


/procsolo está disponible bajo Linux.
chepner

44
@chepner, tendría razón si dijera que /proc/PID/fdno es muy portátil. Pero decir que /procsolo está disponible en Linux no es una declaración correcta.
Graeme

Algunos sitios web usan el <&-formulario, ¿es diferente / necesario?
Lorenzo Pistone

@LorenzoPistone, la dirección no hace ninguna diferencia al cerrar un descriptor, por lo que se puede usar cualquier formulario.
Graeme

5

En versiones recientes de Bash (4.1 y posteriores, año 2009 y posteriores), puede especificar el descriptor de archivo para cerrar usando una variable de shell:

for fd in $(ls /proc/$$/fd/); do
    [ $fd -gt 2 ] && exec {fd}<&-
done

La característica ya había estado en Korn Shell (¿desde 1993?) Pero aparentemente tardó un tiempo en llegar a Bash.


1

Borre todos los descriptores de archivo, excepto i / o / e del shell actual, pero también excluye los proporcionados como argumentos

clear_fds() {
for fd in $(compgen -G "/proc/$BASHPID/fd/*"); do
    fd=${fd/*\/}
        if [[ ! " $* " =~ " ${fd} " ]]; then
            case "$fd" in
                0|1|2|255)
                ;;
                *)
                    eval "exec $fd>&-"
                    ;;
            esac
        fi
done
}

0

Otra forma sin "evaluar" es usar el formulario:

$ exec {var_a}>> file.txt
$ echo $var_a
10
$ ls -l /proc/self/fd/10
l-wx------ 1 0 0 64 Dec 11 18:32 /proc/self/fd/10 -> /run/user/0/tmp/file.txt
$ echo "aaaaa" >&$var_a
$ cat file.txt
aaaaa
$ exec {var_a}>&-
$ ls /proc/self/fd/10
ls: cannot access '/proc/self/fd/10': No such file or directory

Pero esto no cierra todos los descriptores de archivos.
G-Man dice 'Restablecer a Monica' el

En efecto. Tendrá que ejecutar en un ciclo como se explicó en las respuestas anteriores ... Fue solo para señalar el hecho de que "eval" no es obligatorio aquí y que podemos mantener la misma lógica para cerrarlo que para abrirlo. Las páginas de manual realmente no son claras sobre esto ...
David DG

0

No. El kernel puede cerrar solo un FD a la vez, y bash no tiene "comandos de grupo" para los FD.

for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done

Retire el echoy el "después de la prueba.

Si esto no es para el shell en sí, sino para ejecutar un comando, puede usarlo nohup.


2
El descriptor de archivo utilizado por >&-no puede ser un parámetro; la redirección se analiza antes de la expansión del parámetro.
chepner

1
@chepner hoy en día exec {fd}>&-funciona.
jarno
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.