Dateideskriptoren und Shell-Skripte

32

Es fällt mir sehr schwer zu verstehen, wie man Dateideskriptoren in Shell-Skripten verwendet.

Ich kenne die Grundlagen wie

exec 5 > /tmp/foo

Also wird fd 5 zum Schreiben an foo angehängt.

exec 6 < /tmp/bar

… zum Lesen.

exec 5>&-

… Fd schließen.

Was macht das jetzt?

#!/bin/bash

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

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

Wie ich verstehe, &5schließt das fd, also wie wird die Ausgabe nach jedem Aufruf noch erfolgreich umgeleitet?

Dies ist eine Kopie Pasta von: Hier

Es behauptet, dies über eine einfache zu verwenden, echo $a > filewürde es viel schneller machen, ich verstehe es jedoch nicht. Ich würde mich über Links zu anständigen Tutorials freuen. Ich Google-Kräfte scheinen, mich zu verfehlen.

Ricko M
quelle

Antworten:

44

Beachten Sie zunächst, dass die Syntax zum Schließen 5>&-oder 6<&-abhängig davon ist , ob der Dateideskriptor zum Schreiben oder zum Lesen gelesen wird. In diesem Blog-Beitrag scheint es einen Tippfehler oder eine Formatierungsstörung zu geben.

Hier ist das kommentierte Skript.

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                  # 

Hier gibt es keine Schließung. Da sich in diesem einfachen Beispiel alle Ein- und Ausgaben an derselben Stelle befinden, ist die Verwendung zusätzlicher Dateideskriptoren nicht erforderlich. Du könntest schreiben

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

Die Verwendung expliziter Dateideskriptoren ist nützlich, wenn Sie nacheinander in mehrere Dateien schreiben möchten. Angenommen, ein Skript gibt Daten in eine Datenausgabedatei und Protokolldaten in eine Protokolldatei sowie möglicherweise auch Fehlermeldungen aus. Das bedeutet drei Ausgabekanäle: einer für Daten, einer für Protokolle und einer für Fehler. Da es nur zwei Standarddeskriptoren für die Ausgabe gibt, wird ein dritter benötigt. Sie können aufrufen exec, um die Ausgabedateien zu öffnen:

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

Die Bemerkung zur Effizienz ergibt sich, wenn Sie eine Umleitung in einer Schleife haben (vorausgesetzt, die Datei ist zu Beginn leer):

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

Bei jeder Iteration wird das Programm geöffnet /tmp/bar, bis zum Ende der Datei gesucht, einige Daten angehängt und die Datei geschlossen. Es ist effizienter, die Datei ein für alle Mal zu öffnen:

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

Wenn mehrere Umleitungen zu unterschiedlichen Zeiten stattfinden, ist es exechilfreich, die Umleitung aufzurufen , anstatt einen Block in eine Umleitung zu binden.

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

Sie finden mehrere andere Beispiele für die Weiterleitung, indem Sie das io-redirectionTag auf dieser Site durchsuchen .

Gilles 'SO - hör auf böse zu sein'
quelle
1
Beide Syntaxarten zum Schließen des Dateideskriptors bewirken dasselbe.
user1338062