Per salvare un descrittore di file, lo duplicate su un altro fd. Il salvataggio di un percorso nel file corrispondente non è sufficiente, è necessario salvare la modalità di apertura, i flag di apertura, la posizione corrente all'interno del file e così via. E, naturalmente, per pipe o socket anonimi, che non funzionerebbero poiché quelli non hanno percorso. Ciò che si desidera salvare è la descrizione del file aperto a cui fa riferimento il file fd e la duplicazione di un file fd in realtà restituisce un nuovo file fd alla stessa descrizione del file aperto .
Per duplicare un descrittore di file su un altro, con shell tipo Bourne, la sintassi è:
exec 3>&1
Sopra, fd 1 è duplicato su fd 3.
Qualunque fd 3 fosse già aperto prima sarebbe chiuso, ma nota che fds da 3 a 9 (di solito più, fino a 99 con yash
) sono riservati a tale scopo (e non hanno alcun significato speciale in contrasto con 0, 1 o 2), il shell sa di non usarli per il proprio business interno. L'unico motivo per cui fd 3 sarebbe stato aperto in anticipo è perché l'hai fatto nello script 1 o è stato trapelato dal chiamante.
Quindi, puoi cambiare stdout in qualcos'altro:
exec > /dev/null
E più tardi, per ripristinare stdout:
exec >&3 3>&-
( 3>&-
essendo per chiudere il descrittore di file di cui non abbiamo più bisogno).
Ora, il problema è che, tranne in ksh, ogni comando che esegui dopo exec 3>&1
erediterà quel fd 3. Questa è una perdita fd. Generalmente non è un grosso problema, ma ciò può causare problemi.
ksh
imposta il flag close-on-exec su quei fds (per fds oltre 2), ma non altre shell e altre shell non hanno modo di impostarlo manualmente.
Il lavoro per altre shell è chiudere fd 3 per ogni singolo comando, come:
exec 3>&-
exec > file.log
ls 3>&-
uname 3>&-
exec >&3 3>&-
Ingombrante. Qui, il modo migliore sarebbe non usare exec
affatto, ma reindirizzare i gruppi di comandi:
{
ls
uname
} > file.log
Lì, è la shell che si occupa di salvare stdout e ripristinarlo in seguito (e lo fa internamente duplicandolo su un fd (sopra 9, sopra 99 per yash
) con il flag close-on-exec impostato.
Nota 1
Ora, la gestione di questi fds da 3 a 9 può essere ingombrante e problematica se li usi ampiamente o nelle funzioni, specialmente se il tuo script utilizza un codice di terze parti che a sua volta può usare quei fds.
Alcune conchiglie ( zsh
, bash
, ksh93
, tutto aggiunto la funzione ( suggerito da Oliver Kiddle dizsh
) nello stesso periodo nel 2005, dopo che è stato discusso tra loro sviluppatori) hanno una sintassi alternativa per assegnare il primo fd libero al di sopra 10, invece che aiuta in questo caso:
myfunction() {
local fd
exec {fd}>&1
# stdout was duplicated onto a new fd above 10, whose actual value
# is stored in the fd variable
...
# it should even be safe to re-enter the function here
...
exec >&"$fd" {fd}>&-
}