Chiudi tutti i descrittori di file in bash


11

C'è un modo per chiudere tutti i descrittori di file aperti, senza avere un elenco esplicito di loro in anticipo?


4
Tutto che il file descrittori? Ogni processo ne ha alcuni aperti.
Warren Young,

Cosa sono "tutti i descrittori di file aperti"? 0, 1 e 2? O ne hai molti altri? In tal caso, da dove vengono?
U. Windl,

I descrittori di file non vengono chiusi automaticamente al termine dello script?
jarno,

Risposte:


14

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 ttydirettamente 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 stdoute 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 dashI ne ho 10, che indica /dev/ttypiuttosto che lo specifico tty/ ptsdispositivo 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 bashsi espanderà la variabile ma la si considererà parte del comando (in questo caso si proverà al execcomando 0o 1oa 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 lssembra la soluzione migliore qui.

Aggiornare

Per ulteriori informazioni sulla portabilità di /proc/$$/fd, consultare Portabilità dei collegamenti ai descrittori di file . Se /proc/$$/fdnon è 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.
Chepner,

4
@chepner avresti ragione se dicessi che /proc/PID/fdnon è molto portatile. Ma dire che /procè disponibile solo sotto Linux non è un'affermazione corretta.
Graeme,

Alcuni siti Web utilizzano il <&-modulo, è diverso / necessario?
Lorenzo Pistone,

@LorenzoPistone, la direzione non fa differenza quando si chiude un descrittore, quindi è possibile utilizzare entrambi i moduli.
Graeme,

5

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.


1

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
}

0

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

Ma questo non chiude tutti i descrittori di file.
G-Man dice 'Reinstate Monica' l'

Infatti. Dovrai eseguire un ciclo come spiegato nelle risposte precedenti ... Era solo per indicare il fatto che "eval" non è obbligatorio qui e che possiamo mantenere la stessa logica per chiuderlo piuttosto che aprirlo. Le pagine man non sono davvero chiare su questo ...
David DG,

0

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 echoe il "test successivo.

Se questo non è per la shell stessa ma per l'esecuzione di un comando, è possibile utilizzare nohup.


2
Il descrittore di file utilizzato da >&-non può essere un parametro; il reindirizzamento viene analizzato prima dell'espansione dei parametri.
Chepner,

1
Oggi @chepner exec {fd}>&-funziona.
jarno,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.