Warum wird der folgende Befehl nicht beendet? Anstatt zu beenden, läuft die Schleife unbegrenzt.
Während ich dieses Verhalten mithilfe eines komplexeren Setups entdeckte, reduziert sich die einfachste Form des Befehls auf Folgendes.
Wird nicht beendet:
while /usr/bin/true ; do echo "ok" | cat ; done | exit 1
Es gibt oben keine Tippfehler. Jedes '|' ist eine Pfeife. Der 'Exit 1' steht für einen anderen Prozess, der ausgeführt und beendet wurde.
Ich erwarte, dass der "Ausgang 1" ein SIGPIPE in der while-Schleife verursacht (auf eine Pipe ohne Lesegerät schreiben) und dass die Schleife ausbricht. Die Schleife läuft jedoch weiter.
Warum stoppt der Befehl nicht?
linux
command-line
bash
shell
bash-scripting
stephen.z
quelle
quelle
Antworten:
Es liegt an einer Wahl bei der Implementierung.
Das Ausführen des gleichen Skripts unter Solaris mit
ksh93
führt zu einem anderen Verhalten:Was das Problem auslöst, ist die innere Pipeline. Ohne sie wird die Schleife unabhängig von der Shell / dem Betriebssystem beendet:
cat
erhält ein SIGPIPE-Signal unter bash, aber die Shell iteriert die Schleife trotzdem.In der Bash- Dokumentation heißt es:
In der Ksh- Dokumentation heißt es:
POSIX gibt an:
quelle
echo
ignoriert SIGPIPE. Sie können das Problem auch reproduzieren, indem Sieenv echo
anstelle von verwendenecho
(um die Verwendung der eigentlichenecho
Binärdatei zu erzwingen ). (Vergleiche auch die Ausgabe von{ echo hi; echo $? >&2; } | exit 1
und{ env echo hi; echo $? >&2; } | exit 1
.)Dieses Problem nervt mich seit Jahren. Vielen Dank an Jilliagre für den Anstoß in die richtige Richtung.
Wenn ich die Frage auf meiner Linux-Box ein wenig wiederhole, wird dies wie erwartet beendet:
Wenn ich jedoch eine Pipe hinzufüge, wird diese nicht wie erwartet beendet:
Das hat mich jahrelang frustriert. Unter Berücksichtigung der Antwort von Jilliagre kam ich zu diesem wunderbaren Fix:
QED ...
Nicht ganz. Hier ist etwas etwas komplizierter:
Das funktioniert nicht richtig. Ich habe das hinzugefügt,
|| exit
damit es weiß, wie man vorzeitig beendet, aber das allerersteecho
stimmt nicht mit dem überein,grep
sodass die Schleife sofort beendet wird. In diesem Fall interessiert Sie der Exit-Status des nicht wirklichgrep
. Meine Problemumgehung besteht darin, eine weitere hinzuzufügencat
. Also, hier ist ein erfundenes Skript namens "Zehner":Dies wird ordnungsgemäß beendet, wenn es als ausgeführt wird
tens | head
. Danke Gott.quelle