C'è un modo per chiudere tutti i descrittori di file aperti, senza avere un elenco esplicito di loro in anticipo?
C'è un modo per chiudere tutti i descrittori di file aperti, senza avere un elenco esplicito di loro in anticipo?
Risposte:
Per rispondere letteralmente, per chiudere tutti i descrittori di file aperti per bash
:
for fd in $(ls /proc/$$/fd); do
eval "exec $fd>&-"
done
Tuttavia, questa non è una buona idea poiché chiuderà i descrittori di file di base necessari alla shell per l'input e l'output. Se lo fai, nessuno dei programmi che eseguirai avrà il loro output visualizzato sul terminale (a meno che non scrivano tty
direttamente sul dispositivo). Se infatti nei miei test, la chiusura stdin
( exec 0>&-
) causa solo la chiusura di una shell interattiva.
Quello che potresti effettivamente voler fare è piuttosto chiudere tutti i descrittori di file che non fanno parte delle operazioni di base della shell. Questi sono 0 per stdin
, 1 per stdout
e 2 per stderr
. Inoltre, alcune shell sembrano avere altri descrittori di file aperti per impostazione predefinita. In bash
, ad esempio, hai 255 (anche per I / O terminale) e in dash
I ne ho 10, che indica /dev/tty
piuttosto che lo specifico tty
/ pts
dispositivo utilizzato dal terminale. Per chiudere tutto tranne 0, 1, 2 e 255 in bash
:
for fd in $(ls /proc/$$/fd); do
case "$fd" in
0|1|2|255)
;;
*)
eval "exec $fd>&-"
;;
esac
done
Si noti inoltre che eval
è necessario quando si reindirizza il descrittore di file contenuto in una variabile, in caso contrario bash
si espanderà la variabile ma la si considererà parte del comando (in questo caso si proverà al exec
comando 0
o 1
oa qualsiasi descrittore di file che si sta tentando di chiudere).
NOTA: Anche l'utilizzo di un glob anziché ls
(ad es. /proc/$$/fd/*
) Sembra aprire un descrittore di file aggiuntivo per il glob, quindi ls
sembra la soluzione migliore qui.
Per ulteriori informazioni sulla portabilità di /proc/$$/fd
, consultare Portabilità dei collegamenti ai descrittori di file . Se /proc/$$/fd
non è disponibile, una riduzione in sostituzione di $(ls /proc/$$/fd)
, utilizzando lsof
(se disponibile) sarebbe $(lsof -p $$ -Ff | grep f[0-9] | cut -c 2-)
.
/proc
è disponibile solo su Linux.
/proc/PID/fd
non è molto portatile. Ma dire che /proc
è disponibile solo sotto Linux non è un'affermazione corretta.
<&-
modulo, è diverso / necessario?
Nelle versioni recenti di Bash (4.1 e successive, anno 2009 e successive) è possibile specificare il descrittore di file da chiudere usando una variabile di shell:
for fd in $(ls /proc/$$/fd/); do
[ $fd -gt 2 ] && exec {fd}<&-
done
Il film era già nella shell Korn (dal 1993?) Ma a quanto pare ha impiegato del tempo per farsi strada in Bash.
Cancella tutti i descrittori di file tranne i / o / e della shell corrente, ma esclude anche quelli forniti come argomenti
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
}
Un altro modo senza "eval" è usare il modulo:
$ 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
No. Il kernel può chiudere solo un FD alla volta e bash non ha "comandi di gruppo" per gli FD.
for fd in $(ls -1 /proc/27343/fd); do echo exec $fd">&"-; done
Rimuovere il echo
e il "
test successivo.
Se questo non è per la shell stessa ma per l'esecuzione di un comando, è possibile utilizzare nohup
.
>&-
non può essere un parametro; il reindirizzamento viene analizzato prima dell'espansione dei parametri.
exec {fd}>&-
funziona.