Existe-t-il un moyen de fermer tous les descripteurs de fichiers ouverts, sans en avoir préalablement une liste explicite?
Existe-t-il un moyen de fermer tous les descripteurs de fichiers ouverts, sans en avoir préalablement une liste explicite?
Réponses:
Pour répondre littéralement, pour fermer tous les descripteurs de fichiers ouverts pour bash
:
for fd in $(ls /proc/$$/fd); do
eval "exec $fd>&-"
done
Cependant, ce n'est vraiment pas une bonne idée car cela fermera les descripteurs de fichiers de base dont le shell a besoin pour l'entrée et la sortie. Si vous faites cela, aucun des programmes que vous exécutez n'aura leur sortie affichée sur le terminal (à moins qu'ils n'écrivent tty
directement sur le périphérique). Si en fait dans mes tests, la fermeture stdin
( exec 0>&-
) fait juste sortir un shell interactif.
Ce que vous cherchez à faire, c'est plutôt de fermer tous les descripteurs de fichiers qui ne font pas partie des opérations de base du shell. Ce sont 0 pour stdin
, 1 pour stdout
et 2 pour stderr
. En plus de cela, certains shells semblent également avoir d'autres descripteurs de fichiers ouverts par défaut. Dans bash
, par exemple, vous avez 255 (également pour les E / S du terminal) et dans dash
10, ce qui pointe /dev/tty
plutôt que sur le périphérique tty
/ spécifique que pts
le terminal utilise. Pour tout fermer sauf 0, 1, 2 et 255 dans bash
:
for fd in $(ls /proc/$$/fd); do
case "$fd" in
0|1|2|255)
;;
*)
eval "exec $fd>&-"
;;
esac
done
Notez également que eval
nécessaire lors de la redirection du descripteur de fichier contenu dans une variable, sinon bash
étendra la variable mais considérer une partie de la commande (dans ce cas , il essaierait de exec
la commande 0
ou 1
ou tout autre descripteur de fichier que vous essayez de fermer).
REMARQUE: L' utilisation d'un glob à la place de ls
(par exemple /proc/$$/fd/*
) semble également ouvrir un descripteur de fichier supplémentaire pour le glob, donc ls
semble la meilleure solution ici.
Pour plus d'informations sur la portabilité de /proc/$$/fd
, veuillez consulter Portabilité des liens de descripteur de fichier . Si /proc/$$/fd
n'est pas disponible, alors une baisse de remplacement pour le $(ls /proc/$$/fd)
, en utilisant lsof
(si cela est disponible) serait $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)
.
/proc
n'est disponible que sous Linux.
/proc/PID/fd
n'est pas très portable. Mais dire que ce /proc
n'est disponible que sous Linux n'est pas une affirmation correcte.
<&-
formulaire, est-il différent / nécessaire?
Dans les versions récentes de Bash (4.1 et ultérieures, année 2009 et versions ultérieures), vous pouvez spécifier le descripteur de fichier à fermer à l'aide d'une variable shell:
for fd in $(ls /proc/$$/fd/); do
[ $fd -gt 2 ] && exec {fd}<&-
done
Le long métrage était déjà dans le shell Korn (depuis 1993?) Mais avait apparemment pris un certain temps pour faire son chemin dans Bash.
Efface tous les descripteurs de fichiers sauf i / o / e du shell actuel, mais exclut également ceux fournis comme arguments
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
}
Une autre façon sans "eval" du tout, est d'utiliser le formulaire:
$ 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
Non. Le noyau ne peut fermer qu'un seul FD à la fois, et bash n'a pas de "commandes de groupe" pour les FD.
for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done
Retirez le echo
et le "
test après.
Si ce n'est pas pour le shell lui-même mais pour une commande à exécuter, vous pouvez utiliser nohup
.
>&-
ne peut pas être un paramètre; la redirection est analysée avant l'expansion des paramètres.
exec {fd}>&-
fonctionne de nos jours .