Dies ist auf eine Wahl bei der Implementierung zurückzuführen.
Ausführen des gleichen Skripts auf Solaris mit ksh93
erzeugt ein anderes Verhalten:
$ while /usr/bin/true ; do echo "ok" | cat ; done | exit 1
cat: write error [Broken pipe]
Was das Problem auslöst, ist die innere Pipeline, ohne die die Schleife unabhängig von der Shell/dem Betriebssystem beendet wird:
$ while /usr/bin/true ; do echo "ok" ; done | exit 1
$
cat
erhält ein SIGPIPE-Signal unter Bash, aber die Shell wiederholt die Schleife trotzdem.
Process 5659 suspended
[pid 28801] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28801] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28801 detached
Process 28800 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28802 attached
Process 28803 attached
[pid 28803] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
Process 5659 suspended
[pid 28803] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28803 detached
Process 28802 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28804 attached
Process 28805 attached (waiting for parent)
Process 28805 resumed (parent 5659 ready)
Process 5659 suspended
[pid 28805] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28805] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28805 detached
Process 28804 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Bash Dokumentationsstatus:
Die Shell wartet auf alle Befehle in der Pipeline, die beendet werden soll, bevor ein Wert zurückgegeben wird.
Ksh Dokumentationsstatus:
Jeder Befehl, möglicherweise mit Ausnahme des letzten, wird als separater Prozess ausgeführt; die Shell wartet auf den letzten Befehl zu beenden.
POSIX Zustände:
Wenn die Pipeline nicht im Hintergrund läuft (siehe Asynchrone Listen), soll die Shell auf den letzten Befehl warten die in der Pipeline angegeben sind, bis zum Abschluss, und kann auch auf alle Befehle warten zu vervollständigen.
Dieses Problem beschäftigt mich seit Jahren. Danke an Jilliagre für den Schubs in die richtige Richtung.
Um die Frage ein wenig zu wiederholen, wird dies auf meiner Linux-Box wie erwartet beendet:
while true ; do echo "ok"; done | head
Aber wenn ich eine Pipe hinzufüge, tut es das nicht wie erwartet beenden:
while true ; do echo "ok" | cat; done | head
Das hat mich jahrelang frustriert. Unter Berücksichtigung der Antwort von Jilliagre kam ich zu dieser wunderbaren Lösung:
while true ; do echo "ok" | cat || exit; done | head
Q.E.D. ...
Nicht ganz. Hier ist etwas komplizierter:
i=0
while true; do
i=`expr $i + 1`
echo "$i" | grep '0$' || exit
done | head
Das funktioniert nicht richtig. Ich habe den || exit
hinzugefügt es weiß also, wie es vorzeitig beendet wird, aber das allererste echo
stimmt nicht mit grep
überein Die Schleife wird also sofort beendet. In diesem Fall interessiert Sie der Exit-Status von grep
wirklich nicht . Meine Problemumgehung besteht darin, einen weiteren cat
hinzuzufügen . Also, hier ist ein erfundenes Skript namens "tens":
#!/bin/bash
i=0
while true; do
i=`expr $i + 1`
echo "$i" | grep '0$' | cat || exit
done
Dies wird ordnungsgemäß beendet, wenn es als tens | head
ausgeführt wird . Gott sei Dank.