Feche todos os descritores de arquivo no bash

11

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

Lorenzo Pistone
fonte
4
Tudo que descritores de arquivo? Todo processo tem algum aberto.
Warren novo
O que são "todos os descritores de arquivos abertos"? 0, 1 e 2? Ou você tem muito mais? Se sim, de onde eles vieram?
U. Windl 06/02/19
Os descritores de arquivo não são fechados automaticamente quando o script termina?
27419 jarno

Respostas:

14

Para responder literalmente, feche todos os 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 arquivo básicos que o shell precisa para entrada e saída. Se você fizer isso, nenhum dos programas executados terá a saída exibida no terminal (a menos que escreva ttydiretamente no dispositivo). Se fato em meus testes, o fechamento stdin( exec 0>&-) apenas faz com que um shell interativo saia.

O que você realmente deseja 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 stdoute 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ê possui 255 (também para o terminal de E / S) e em dash10, que aponta para /dev/ttyo dispositivo tty/ ptsdispositivo específico 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

Note também que evalé necessária quando redirecionando o descritor de arquivo contido em uma variável, se não bashirá expandir a variável, mas considerá-lo parte do comando (neste caso, seria tentar execo comando 0ou 1ou qualquer descritor de arquivo que você está tentando fechar).

NOTA: O uso de um globo em vez de ls(por exemplo /proc/$$/fd/*) parece abrir um descritor de arquivo extra para o globo, assim lsparece a melhor solução aqui.

Atualizar

Para obter mais informações sobre portabilidade /proc/$$/fd, consulte Portabilidade dos links do descritor de arquivos . Se /proc/$$/fdnão estiver disponível, seria uma queda no substituto de $(ls /proc/$$/fd), usando lsof(se disponível) $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-).

Graeme
fonte
/procestá disponível apenas no Linux.
Chepner # 7/14
4
@chepner, você estaria certo se dissesse que /proc/PID/fdnão é muito portátil. Mas dizer que /procsó está disponível no Linux não é uma afirmação correta.
Graeme
Alguns sites usam o <&-formulário, é diferente / necessário?
Lorenzo Pistone 07/04
@LorenzoPistone, a direção não faz diferença ao fechar um descritor, para que qualquer formulário possa ser usado.
Graeme
5

Nas versões recentes do Bash (4.1 e seguintes, ano de 2009 e posteriores), você pode especificar o descritor de arquivo a ser fechado 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.

tetsujin
fonte
1

Limpe todos os descritores de arquivo, exceto i / o / e do shell atual, mas também exclui os 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
}
desenterrar
fonte
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
David DG
fonte
Mas isso não fecha todos os descritores de arquivo.
G-Man diz 'Reinstate Monica'
De fato. Você terá que executar um loop como explicado nas respostas anteriores ... Foi apenas para apontar o fato de que "eval" não é obrigatório aqui e que podemos manter a mesma lógica para fechá-lo do que abri-lo. . páginas homem realmente não são claras sobre isso ...
David DG
0

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

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

Remova o echoe o "após o teste.

Se não for para o próprio shell, mas para que um comando seja executado, você poderá usá-lo nohup.

Hauke ​​Laging
fonte
2
O descritor de arquivo usado por >&-não pode ser um parâmetro; o redirecionamento é analisado antes da expansão do parâmetro.
chepner
1
Atualmente, o @chepner exec {fd}>&-funciona.
27419 jarno