Zwei Fenster, derselbe Benutzer, mit Bash-Eingabeaufforderungen. Geben Sie in Fenster 1 Folgendes ein:
$ mkfifo f; exec <f
Bash versucht nun, aus dem Dateideskriptor 0 zu lesen, der der Named Pipe zugeordnet ist f
. Geben Sie in Fenster 2 Folgendes ein:
$ echo ls > f
Jetzt druckt Fenster 1 ein ls und dann stirbt die Shell. Warum?
Nächstes Experiment: Öffnen Sie Fenster-1 erneut mit exec <f
. Geben Sie in Fenster 2 Folgendes ein:
$ exec 3>f
$ echo ls >&3
Nach der ersten Zeile oben wird Fenster 1 aktiviert und eine Eingabeaufforderung gedruckt. Warum? Nach der zweiten Zeile oben druckt Fenster-1 die ls
Ausgabe und die Shell bleibt am Leben. Warum? Tatsächlich schließt jetzt in Fenster-2 echo ls > f
die Fenster-1-Shell nicht.
Die Antwort muss mit der Existenz des Dateideskriptors 3 aus Fenster 2 zu tun haben, der auf die Named Pipe verweist?!
quelle
exec <f
,bash
nicht versucht , lesen ausf
, wird zunächst versucht , öffnen es. Dasopen()
wird erst zurückkehren, wenn ein Prozess ein weiteres Öffnen im Schreibmodus für die Pipe ausführt (an diesem Punkt wird die Pipe instanziiert und die Shell liest Eingaben von ihr).exec 3>f
die erste Shell nach dem Ausführen eine Eingabeaufforderung ausgibt. (Kleiner Punkt,Antworten:
Dies hat mit dem Schließen des Dateideskriptors zu tun .
In Ihrem ersten Beispiel wird
echo
in den Standardausgabestream geschrieben, mit dem die Shell geöffnet wird, um eine Verbindung herzustellen.f
Wenn sie beendet wird, wird der Deskriptor (von der Shell) geschlossen. Auf der Empfangsseite wird die Shell, die Eingaben aus ihrem Standardeingabestream (verbunden mitf
) liestls
, ausgeführt, ausgeführtls
und dann aufgrund der Bedingung für das Dateiende auf ihrer Standardeingabe beendet.Die Dateiende-Bedingung tritt auf, weil alle Writer der Named Pipe (in diesem Beispiel nur einer) ihr Pipe-Ende geschlossen haben.
In Ihrem zweiten Beispiel
exec 3>f
öffnet Deskriptordatei 3 zum Schreiben auff
, dannecho
schreibtls
es. Es ist die Shell, in der jetzt der Dateideskriptor geöffnet ist, nicht derecho
Befehl. Der Deskriptor bleibt geöffnet, bis Sie dies tunexec 3>&-
. Auf der Empfangsseite wird die Shell, die Eingaben aus ihrem Standardeingabestream (verbunden mitf
) liestls
, ausgeführtls
und wartet dann auf weitere Eingaben (da der Stream noch offen ist).Der Stream bleibt offen, da alle Autoren (die Shell, via
exec 3>f
undecho
) ihr Ende der Pipe nicht geschlossen haben (exec 3>f
ist noch in Kraft).Ich habe
echo
oben darüber geschrieben, als wäre es ein externer Befehl. Es ist höchstwahrscheinlich in die Shell eingebaut. Der Effekt ist jedoch der gleiche.quelle
Es gibt nicht viel zu tun: Wenn es keine Writer für die Pipe gibt, sieht sie für die Leser geschlossen aus, dh sie gibt beim Lesen EOF zurück und blockiert beim Öffnen.
Von der Linux-Manpage (
pipe(7)
siehe aber auchfifo(7)
):Das Schließen des Schreibendes geschieht implizit am Ende des
echo ls >f
, und wie Sie sagen, wird im anderen Fall der Dateideskriptor offen gehalten.quelle
Nachdem ich die beiden Antworten von @Kusalananda und @ikkachu gelesen habe, glaube ich zu verstehen. In Fenster 1 wartet die Shell darauf, dass etwas das Schreibende der Pipe öffnet und dann schließt. Sobald das Schreibende geöffnet ist, druckt die Shell in Fenster 1 eine Eingabeaufforderung. Sobald das Schreibende geschlossen ist, erhält die Shell EOF und stirbt.
Auf der Fenster-2-Seite haben wir die beiden in meiner Frage beschriebenen Situationen: In der ersten Situation mit
echo ls > f
gibt es keinen Dateideskriptor 3, also haben wirecho
Laichen,stdin
und esstdout
sieht so aus:Dann
echo
endet und die Schale schließt beide Deskriptoren. Da der Dateideskriptor 1 geschlossen ist und referenziertf
, ist das Schreibende vonf
geschlossen, und dies führt dazu, dass ein EOF zu Fenster 1 wechselt.In der zweiten Situation laufen wir
exec 3>f
in unserer Shell, wodurch die Shell diese Umgebung annimmt:Jetzt führen wir aus
echo ls >& 3
und die Shell weist Dateideskriptorenecho
wie folgt zu:Dann schließt die Shell die drei obigen Deskriptoren, einschließlich
f
, hat aberf
immer noch einen Verweis darauf von der Shell selbst. Das ist der wichtige Unterschied. Das Schließen von Deskriptor 3 mitexec 3>&-
würde die letzte offene Referenz schließen und einen EOF zu Fenster 1 führen, wie @Kusalananda feststellte.quelle