Gestern habe ich diesen SO-Kommentar gelesen, der besagt, dass in der Shell (mindestens bash
) >&-
„hat dasselbe Ergebnis wie“ >/dev/null
.
Dieser Kommentar bezieht sich tatsächlich auf den ABS-Leitfaden als Quelle seiner Informationen. Aber diese Quelle sagt, dass >&-
Syntax „schließt Dateideskriptoren“.
Mir ist nicht klar, ob die beiden Aktionen, einen Dateideskriptor zu schließen und ihn auf das Nullgerät umzuleiten, völlig gleichwertig sind. Meine Frage ist also:Sind sie es?
An der Oberfläche scheint es, dass das Schließen eines Deskriptors wie das Schließen einer Tür ist, aber das Umleiten auf ein Nullgerät öffnet eine Tür in die Schwebe! Die beiden scheinen mir nicht genau gleich zu sein, denn wenn ich eine geschlossene Tür sehe, werde ich nicht versuchen, etwas herauszuwerfen, aber wenn ich eine offene Tür sehe, gehe ich davon aus, dass ich es kann.
Mit anderen Worten, ich habe mich immer gefragt, ob >/dev/null
bedeutet, dass cat mybigfile >/dev/null
würde tatsächlich jedes Byte der Datei verarbeiten und es nach /dev/null
schreiben der es vergisst. Wenn die Shell andererseits auf einen geschlossenen Dateideskriptor trifft, neige ich zu der Annahme (bin mir aber nicht sicher), dass sie einfach nichts schreiben wird, obwohl die Frage bleibt, ob cat
wird immer noch lesen jedes Byte.
Dieser Kommentar lautet >&-
und >/dev/null
„sollte “ sei die gleiche, aber es ist keine so durchschlagende Antwort für mich. Ich hätte gerne eine maßgeblichere Antwort mit einem Hinweis auf Standard- oder Quellkern oder nicht …
Akzeptierte Antwort:
Nein, ganz bestimmt nicht möchte die Dateideskriptoren 0, 1 und 2 schließen.
Wenn Sie dies tun, wird die Anwendung beim ersten Öffnen einer Datei zu stdin/stdout/stderr…
Wenn Sie beispielsweise Folgendes tun:
echo text | tee file >&-
Beim tee
(zumindest einige Implementierungen, wie busybox’) öffnet die Datei zum Schreiben, sie wird auf Dateideskriptor 1 (stdout) geöffnet. Also tee
schreibt text
zweimal 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) = ?
Es ist bekannt, dass dies Sicherheitslücken verursacht. Zum Beispiel:
chsh 2>&-
Und chsh
(eine setuid-Anwendung) kann am Ende Fehlermeldungen in /etc/passwd
schreiben .
Einige Tools und sogar einige Bibliotheken versuchen, sich dagegen zu wehren. Zum Beispiel GNU tee
verschiebt den Dateideskriptor auf einen über 2, wenn den Dateien, die es zum Schreiben öffnet, 0, 1, 2 zugewiesen sind, während busybox tee
ist nicht.
Die meisten Tools melden, wenn sie nicht auf stdout schreiben können (weil es zum Beispiel nicht geöffnet ist), eine Fehlermeldung auf stderr (in der Sprache des Benutzers, was zusätzliche Verarbeitung zum Öffnen und Analysieren von Lokalisierungsdateien bedeutet …), also wird es erheblich weniger effizient sein und möglicherweise dazu führen, dass das Programm fehlschlägt.
Effizienter wird es jedenfalls nicht. Das Programm wird immer noch ein write()
ausführen Systemaufruf. Es kann nur effizienter sein, wenn das Programm das Schreiben auf stdout/stderr nach dem ersten fehlgeschlagenen write()
aufgibt Systemaufruf, aber Programme tun das im Allgemeinen nicht. Sie beenden sich im Allgemeinen entweder mit einem Fehler oder versuchen es weiter.