Feche todos os descritores de arquivos no bash

10

Existe uma maneira de fechar todos os descritores de arquivos abertos, sem ter uma lista explícita deles de antemão?

    
por Lorenzo Pistone 06.04.2014 / 19:48

5 respostas

13

Para responder literalmente, para fechar todos descritores de arquivos abertos para bash :

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

No entanto, isso realmente não é uma boa ideia, pois fechará os descritores de arquivos básicos que o shell precisa para entrada e saída. Se você fizer isso, nenhum dos programas executados terá sua saída exibida no terminal (a menos que eles gravem diretamente no dispositivo tty ). Se o fato de meus testes fecharem stdin ( exec 0>&- ) apenas faz com que um shell interativo saia.

O que você pode realmente querer fazer é fechar todos os descritores de arquivos que não fazem parte da operação básica do shell. Estes são 0 para stdin , 1 para stdout e 2 para stderr . Além disso, alguns shells também parecem ter outros descritores de arquivos abertos por padrão. Em bash , por exemplo, você tem 255 (também para terminal I / O) e em dash eu tenho 10, que aponta para /dev/tty em vez do dispositivo específico tty / pts que o terminal está usando . Para fechar tudo além de 0, 1, 2 e 255 em bash :

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

Observe também que eval é necessário ao redirecionar o descritor de arquivo contido em uma variável, se não bash expandirá a variável, mas a considerará parte do comando (nesse caso, ela tentaria exec o comando 0 ou 1 ou qualquer descritor de arquivo que você esteja tentando fechar).

OBSERVAÇÃO: Também usando um glob em vez de ls (ex. /proc/$$/fd/* ) parece abrir um descritor de arquivo extra para o glob, então ls parece a melhor solução aqui.

Atualizar

Para mais informações sobre a portabilidade de /proc/$$/fd , consulte Portabilidade do descritor de arquivo links . Se /proc/$$/fd estiver indisponível, uma substituição no $(ls /proc/$$/fd) , usando lsof (se disponível), será $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-) .

    
por 06.04.2014 / 22:36
5

Em versões recentes do Bash (4.1 e posteriores, ano 2009 e posterior) você pode especificar o descritor de arquivo para fechar usando uma variável de shell:

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

O recurso já estava no shell Korn (desde 1993?), mas aparentemente levou algum tempo para entrar no Bash.

    
por 31.03.2016 / 00:30
1

Limpa todos os descritores de arquivos, exceto i / o / e do shell atual, mas também exclui aqueles fornecidos 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
}
    
por 10.03.2018 / 11:36
0

Não. O kernel pode fechar apenas um FD de cada vez, e o bash não tem "comandos de grupo" para FDs.

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

Remova o echo após o teste.

Se isso não for para o shell em si, mas para um comando ser executado, você poderá usar nohup .

    
por 06.04.2014 / 20:51
0

Outra maneira sem "eval" é usar o formulário:

$ 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
    
por 11.12.2018 / 18:40