Descripteurs de fichiers et scripts shell

32

J'ai beaucoup de difficulté à comprendre comment utiliser les descripteurs de fichiers dans les scripts shell.

Je connais les bases telles que

exec 5 > /tmp/foo

Donc, fd 5 est attaché à foo pour écrire.

exec 6 < /tmp/bar

… a lire.

exec 5>&-

… Proche fd.

Maintenant qu'est-ce que cela fait?

#!/bin/bash

exec 5 > /tmp/foo 
exec 6 < /tmp/bar 

cat <&6 | while read a
do
     echo $a >&5
done

&5Si je comprends bien ferme le fd, alors comment la sortie est-elle toujours redirigée avec succès après chaque appel?

Ceci est une copie de pâtes de: ici

Il affirme que si on utilisait cela par-dessus un simple, cela echo $a > fileserait beaucoup plus rapide, mais je ne parviens pas à comprendre. J'apprécierais tous les liens au tutoriel décent. Je google pouvoirs semblent me manquer.

Ricko M
la source

Réponses:

44

Tout d’abord, notez que la syntaxe de fermeture est 5>&-ou 6<&-, selon que le descripteur de fichier est lu en écriture ou en lecture. Il semble y avoir une faute de frappe ou un problème de formatage dans cet article de blog.

Voici le script commenté.

exec 5>/tmp/foo       # open /tmp/foo for writing, on fd 5
exec 6</tmp/bar       # open /tmp/bar for reading, on fd 6
cat <&6 |             # call cat, with its standard input connected to
                      # what is currently fd 6, i.e., /tmp/bar
while read a; do      # 
  echo $a >&5         # write to fd 5, i.e., /tmp/foo
done                  # 

Il n'y a pas de fermeture ici. Étant donné que toutes les entrées et les sorties se trouvent au même endroit dans cet exemple simple, l'utilisation de descripteurs de fichier supplémentaires n'est pas nécessaire. Tu pourrais écrire

cat </tmp/bar |
while read a; do
  echo $a
done >/tmp/foo

L'utilisation de descripteurs de fichier explicites devient utile lorsque vous souhaitez écrire successivement dans plusieurs fichiers. Par exemple, considérons un script qui génère des données dans un fichier de sortie de données et enregistre les données dans un fichier journal et éventuellement des messages d'erreur. Cela signifie trois canaux de sortie: un pour les données, un pour les journaux et un pour les erreurs. Comme il n'y a que deux descripteurs standard pour la sortie, un troisième est nécessaire. Vous pouvez appeler execpour ouvrir les fichiers de sortie:

exec >data-file
exec 3>log-file
echo "first line of data"
echo "this is a log line" >&3

if something_bad_happens; then echo error message >&2; fi
exec >&-  # close the data output file
echo "output file closed" >&3

La remarque sur l'efficacité apparaît lorsque vous avez une redirection dans une boucle, comme ceci (supposons que le fichier est vide pour commencer):

while …; do echo $a >>/tmp/bar; done

À chaque itération, le programme s'ouvre /tmp/bar, cherche la fin du fichier, ajoute des données et ferme le fichier. Il est plus efficace d’ouvrir le fichier une fois pour toutes:

while …; do echo $a; done >/tmp/bar

Lorsque plusieurs redirections se produisent à des moments différents, il execest utile d' appeler pour effectuer des redirections plutôt que d'encapsuler un bloc dans une redirection.

exec >/tmp/bar
while …; do echo $a; done

Vous trouverez plusieurs autres exemples de redirection en parcourant la io-redirectionbalise sur ce site .

Gilles, arrête de faire le mal
la source
1
Soit la syntaxe de fermeture du descripteur de fichier fait la même chose.
user1338062