Ieri ho letto questo commento SO che dice che nella shell (almeno bash
) >&-
"ha lo stesso risultato di" >/dev/null
.
Tale commento si riferisce in realtà alla guida dell'ABS come fonte delle sue informazioni. Ma quella fonte dice che il >&-
sintassi "chiude i descrittori di file".
Non mi è chiaro se le due azioni di chiudere un descrittore di file e reindirizzarlo al dispositivo nullo siano totalmente equivalenti. Quindi la mia domanda è:lo sono?
A prima vista sembra che chiudere un descrittore sia come chiudere una porta, ma reindirizzarlo a un dispositivo nullo sia aprire una porta per il limbo! I due non mi sembrano esattamente la stessa cosa perché se vedo una porta chiusa non cercherò di buttarci fuori niente, ma se vedo una porta aperta presumo di poterlo fare.
In altre parole, mi sono sempre chiesto se >/dev/null
significa che cat mybigfile >/dev/null
elaborerebbe effettivamente ogni byte del file e lo scriverebbe in /dev/null
che lo dimentica. D'altra parte, se la shell incontra un descrittore di file chiuso, tendo a pensare (ma non sono sicuro) che semplicemente non scriverà nulla, anche se rimane la domanda se cat
continuerà a leggere ogni byte.
Questo commento dice >&-
e >/dev/null
“dovrebbe ” essere lo stesso, ma non è una risposta così clamorosa per me. Mi piacerebbe avere una risposta più autorevole con qualche riferimento al core standard o sorgente o meno...
Risposta accettata:
No, certamente non vuoi chiudere i descrittori di file 0, 1 e 2.
Se lo fai, la prima volta che l'applicazione apre un file, diventerà stdin/stdout/stderr…
Ad esempio, se lo fai:
echo text | tee file >&-
Quando tee
(almeno alcune implementazioni, come busybox') apre il file per la scrittura, sarà aperto sul descrittore di file 1 (stdout). Quindi tee
scriverà text
due volte in file
:
$ echo text | strace tee file >&-
[...]
open("file", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 1
read(0, "textn", 8193) = 5
write(1, "textn", 5) = 5
write(1, "textn", 5) = 5
read(0, "", 8193) = 0
exit_group(0) = ?
Questo è noto per causare vulnerabilità di sicurezza. Ad esempio:
chsh 2>&-
E chsh
(un'applicazione setuid) potrebbe finire per scrivere messaggi di errore in /etc/passwd
.
Alcuni strumenti e persino alcune librerie cercano di proteggersi da questo. Ad esempio GNU tee
sposterà il descrittore di file su uno sopra 2 se i file che apre per la scrittura sono assegnati 0, 1, 2 mentre busybox tee
non lo farà.
La maggior parte degli strumenti, se non possono scrivere su stdout (perché ad esempio non è aperto), segnaleranno un messaggio di errore su stderr (nella lingua dell'utente che significa elaborazione extra per aprire e analizzare i file di localizzazione...), quindi lo farà essere significativamente meno efficiente e possibilmente causare il fallimento del programma.
In ogni caso, non sarà più efficiente. Il programma eseguirà comunque un write()
chiamata di sistema. Può essere più efficiente solo se il programma smette di scrivere su stdout/stderr dopo il primo write()
fallito chiamata di sistema, ma i programmi generalmente non lo fanno. Generalmente escono con un errore o continuano a provare.