GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum wird eine Bash-While-Schleife nicht beendet, wenn sie zu einem beendeten Unterbefehl weitergeleitet wird?

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.


Linux
  1. Linux-Scripting:3 Anleitungen für While-Schleifen in Bash

  2. Warum wird das Bash-Skript nach der Ausführung nicht beendet?

  3. Warum liefert xargs -L das richtige Format und xargs -n nicht?

  4. So erhalten Sie den Exit-Status in einer Bash-Schleife

  5. Bash:Schleife, bis der Befehlsausgangsstatus gleich 0 ist

Bash Break:So verlassen Sie eine Schleife

Bash-while-Schleife

Bash bis Loop

Bash-Skripting – While- und Until-Schleife mit Beispielen erklärt

Bash:Warum wird das übergeordnete Skript nicht bei SIGINT beendet, wenn das untergeordnete Skript SIGINT abfängt?

Shell-Skript While-Schleife:[um eine Pipeline herum fehlt `]'