
Um die Frage im Titel klarzustellen: Ich verstehe, warum Ersteres stirbt. Ich verstehe nicht, warum Letzteres nicht stirbt, nur weil ein | cat
zum Schleifenkörper hinzugefügt wird.
Auch vielleicht damit verbunden,
while true; do echo y; done
stirbt sofort, wenn ich das tue ^C
, aber das Töten
while true; do echo y | cat; done
oft muss man ^C
mehr als einmal drücken. Manchmal klappt es einmal, manchmal 2 oder 3 Mal, und dann gibt es Zeiten, in denen ich ^C
eine Weile warten muss, bis es stirbt.
Beide Verhaltensweisen treten sowohl bei Bash als auch bei Zsh auf, obwohl das ^C
eine bei Bash seltener aufzutreten scheint.
Für beide Verhaltensweisen ist dies nicht auf das Hinzufügen des Pipe-Zeichens beschränkt cat
. | dd
, | tee
, usw. verursachen sie auch. echo y | true
Es verursacht sie sogar. Es scheint die Anwesenheit eines Pipe-Zeichens im Schleifenkörper zu sein.
Warum ändert das Vorhandensein eines Rohrs in einem Schleifenkörper die Reaktion der Schleife auf Signale?
Antwort1
while true; do echo y; done | true
Da in echo
integriert ist, können Sie einen Subshell-Prozess ausführen, der y\n
in einer Schleife in eine Pipe schreibt.
Bei true
der Rückkehr ist das Leseende dieser Pipe geschlossen, sodass das Schreiben an das Schreibende dazu führt, dass ein SIGPIPE
an den Schreibprozess übergeben wird. Hier ist das der Subshell-Prozess, der die Schleife ausführt.
In while true; do echo y | cat; done | true
ist es cat
das, was in die Pipe schreibt. cat
ist im Allgemeinen nicht integriert, und selbst wenn es das wäre, werden in anderen Shells als zsh und ksh alle Pipe-Komponenten immer in untergeordneten Prozessen ausgeführt.
Hier wird also nur der laufende Prozess cat
beendet und der Subshell-Prozess, der die Schleife ausführt, führt weiterhin weitere cat
Prozesse aus, die beendet werden, sobald sie y\n
auf ihre Standardausgabe schreiben.
Wenn Sie in ksh93/ksh2020 Folgendes tun:
$ builtin cat
$ type cat
cat is a shell builtin
$ set -o pipefail
$ while true; do echo y | cat; done | true; kill -l "$?"
PIPE
Dieses Mal cat
ist es integriert und wird im selben Prozess wie die Schleife ausgeführt (wie auch cat
der Befehl ganz rechts in der ersten Pipezeile, und ksh führt diesen nicht in einer Subshell aus), sodass die Subshell-Pipes true
beendet werden und kill -l
bestätigen, dass sie durch ein SIGPIPE beendet wurde.