Um einen Dateideskriptor zu speichern, duplizieren Sie ihn auf einem anderen fd. Das Speichern eines Pfads zur entsprechenden Datei reicht nicht aus. Sie müssen den Öffnungsmodus, die Öffnungsflags, die aktuelle Position in der Datei usw. speichern. Und natürlich würde das bei anonymen Pipes oder Sockets nicht funktionieren, da diese keinen Pfad haben. Was Sie speichern möchten, ist die offene Dateibeschreibung , auf die sich die FD bezieht, und das Duplizieren einer FD gibt tatsächlich eine neue FD an dieselbe offene Dateibeschreibung zurück .
Um einen Dateideskriptor mit einer Bourne-ähnlichen Shell auf einen anderen zu duplizieren, lautet die Syntax wie folgt:
exec 3>&1
Oben ist fd 1 auf fd 3 dupliziert.
Was auch immer fd 3 zuvor bereits geöffnet war, wird geschlossen. Beachten Sie jedoch, dass fds 3 bis 9 (normalerweise mehr, bis zu 99 mit yash
) für diesen Zweck reserviert sind (und entgegen 0, 1 oder 2 keine spezielle Bedeutung haben) Shell weiß, dass sie nicht für interne Zwecke eingesetzt werden dürfen. Der einzige Grund, warum fd 3 zuvor geöffnet gewesen wäre, ist, dass Sie es in Skript 1 getan haben oder dass es vom Aufrufer durchgesickert ist.
Dann können Sie stdout in etwas anderes ändern:
exec > /dev/null
Und später, um stdout wiederherzustellen:
exec >&3 3>&-
( 3>&-
um den Dateideskriptor zu schließen, den wir nicht mehr benötigen).
Das Problem dabei ist, dass außer in ksh jeder Befehl, den Sie danach ausführen, exec 3>&1
das fd 3 erbt. Das ist ein fd-Leck. Im Allgemeinen keine große Sache, aber das kann zu Problemen führen.
ksh
setzt das Close-On-Exec- Flag auf diesen FDS (für FDS über 2), aber andere Shells und andere Shells haben keine Möglichkeit, dieses Flag manuell zu setzen.
Die Arbeit für die andere Shell besteht darin, fd 3 für jeden einzelnen Befehl zu schließen, wie zum Beispiel:
exec 3>&-
exec > file.log
ls 3>&-
uname 3>&-
exec >&3 3>&-
Schwerfällig. Hier wäre der beste Weg, überhaupt nicht zu verwenden exec
, sondern Befehlsgruppen umzuleiten:
{
ls
uname
} > file.log
Dort ist es die Shell, die dafür sorgt, dass stdout gespeichert und anschließend wiederhergestellt wird (und dies geschieht intern, indem es auf einem fd (über 9, über 99 für yash
) mit gesetztem Flag close-on-exec dupliziert wird ).
Anmerkung 1
Jetzt kann die Verwaltung dieser FDS 3 bis 9 mühsam und problematisch sein, wenn Sie sie ausgiebig oder in Funktionen verwenden, insbesondere wenn Ihr Skript Code von Drittanbietern verwendet, der diese FDS wiederum verwenden kann.
Einige Schalen ( zsh
, bash
, ksh93
, alle Features (hinzugefügt vorgeschlagen von Oliver Kiddle vonzsh
) etwa zur gleichen Zeit im Jahr 2005 , nachdem sie unter ihren Entwicklern diskutiert wurden) eine alternative Syntax , um die erste freie fd über 10 statt zuzuordnen , die in diesem Fall hilft:
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}>&-
}