Hier, j'ai lu ce commentaire SO qui dit que dans le shell (au moins bash
) >&-
"a le même résultat que" >/dev/null
.
Ce commentaire fait en fait référence au guide ABS comme source de ses informations. Mais cette source dit que le >&-
syntaxe "ferme les descripteurs de fichiers".
Il ne m'est pas clair si les deux actions consistant à fermer un descripteur de fichier et à le rediriger vers le périphérique nul sont totalement équivalentes. Donc ma question est :le sont-ils ?
À première vue, il semble que fermer un descripteur, c'est comme fermer une porte, mais le rediriger vers un périphérique nul, c'est ouvrir une porte vers les limbes ! Les deux ne me semblent pas exactement identiques, car si je vois une porte fermée, je n'essaierai pas d'en jeter quoi que ce soit, mais si je vois une porte ouverte, je supposerai que je peux.
En d'autres termes, je me suis toujours demandé si >/dev/null
signifie que cat mybigfile >/dev/null
traiterait en fait chaque octet du fichier et l'écrirait dans /dev/null
qui l'oublie. D'un autre côté, si le shell rencontre un descripteur de fichier fermé, j'ai tendance à penser (mais je ne suis pas sûr) qu'il n'écrira tout simplement rien, bien que la question reste de savoir si cat
va encore lire chaque octet.
Ce commentaire dit >&-
et >/dev/null
"devrait ” être le même, mais ce n'est pas une réponse si retentissante pour moi. J'aimerais avoir une réponse plus autoritaire avec une référence au noyau standard ou source ou non…
Réponse acceptée :
Non, certainement pas souhaitez fermer les descripteurs de fichiers 0, 1 et 2.
Si vous le faites, la première fois que l'application ouvrira un fichier, il deviendra stdin/stdout/stderr…
Par exemple, si vous faites :
echo text | tee file >&-
Quand tee
(au moins certaines implémentations, comme busybox') ouvre le fichier en écriture, il sera ouvert sur le descripteur de fichier 1 (stdout). Alors tee
écrira text
deux fois dans 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) = ?
Cela a été connu pour causer des vulnérabilités de sécurité. Par exemple :
chsh 2>&-
Et chsh
(une application setuid) peut finir par écrire des messages d'erreur dans /etc/passwd
.
Certains outils et même certaines bibliothèques essaient de s'en prémunir. Par exemple GNU tee
déplacera le descripteur de fichier vers un au-dessus de 2 si les fichiers qu'il ouvre pour l'écriture sont assignés 0, 1, 2 tandis que busybox tee
ne le fera pas.
La plupart des outils, s'ils ne peuvent pas écrire sur stdout (parce que, par exemple, il n'est pas ouvert), signaleront un message d'erreur sur stderr (dans la langue de l'utilisateur, ce qui signifie un traitement supplémentaire pour ouvrir et analyser les fichiers de localisation…), il sera donc être nettement moins efficace et éventuellement entraîner l'échec du programme.
Dans tous les cas, ce ne sera pas plus efficace. Le programme fera toujours un write()
appel système. Cela ne peut être que plus efficace si le programme abandonne l'écriture sur stdout/stderr après le premier échec write()
appel système, mais les programmes ne le font généralement pas. Ils quittent généralement avec une erreur ou continuent d'essayer.