Warum stoppt eine while-Schleife, nachdem sie angehalten wurde?

10

Warum wird die Schleife bei Verwendung von Bash und Anhalten einer while-Schleife gestoppt, nachdem sie fortgesetzt wurde? Kurzes Beispiel unten.

$ while true; do echo .; sleep 1; done
.
.
^Z
[1]+  Stopped                 sleep 1
$ fg
sleep 1
$

Ich bin mit Signalen vertraut und ich vermute, dass dies das natürliche Verhalten von Bash ist, aber ich möchte besser verstehen, warum es sich so verhält.

bkzland
quelle
weil es einen Interrupt behandeln muss und diesen bei der $?Rückkehr genau wiedergeben muss , und so trueist es dann nicht true. wahrscheinlich. Meiner Ansicht nach.
Mikeserv
1
Ich hoffe, dieser Kommentar wird nicht markiert, aber ich werde Ihre Frage mit einer anderen Frage im Unix-Koan-Stil beantworten: "Warum hört ein Schüler auf, auf dem Spielplatz zu kämpfen, nachdem er suspendiert wurde?" Die Antwort ist, weil er nicht mehr auf dem Spielplatz ist, auf dem er Kämpfe beginnen kann. Somit wurde das fragliche Verhalten einfach gestoppt.
Rubynorails
Sie stoppen den Befehl, die Schleife ist unterbrochen. Dann setzen Sie den Befehl single sleep 1 fort, nicht die Schleife.
123
1
Relevant
123

Antworten:

10

Dies sieht aus wie ein Fehler in mehreren Shells, es funktioniert wie erwartet mit ksh93 und zsh .

Hintergrund:

Die meisten Shells scheinen die while-Schleife innerhalb der Haupt-Shell und auszuführen

Bourne Shell setzt die gesamte Shell aus, wenn Sie ^ Z mit einer Nicht-Login-Shell eingeben

bash unterbricht nur die sleepund verlässt dann die while-Schleife, um eine neue Shell-Eingabeaufforderung zu drucken

dash macht diesen Befehl nicht suspendierbar

Mit ksh93 funktionieren die Dinge ganz anders:

ksh93 macht dasselbe, während der Befehl zum ersten Mal gestartet wird, aber wie sleepein Buitin in ksh93 hat ksh93 einen Handler, der bewirkt, dass die while-Schleife die Haupt-Shell abzweigt und dann zum Zeitpunkt der Eingabe von ^ Z angehalten wird.

Wenn Sie später in ksh93 eingebenfg , wird das gegabelte untergeordnete Element , das die Schleife noch ausführt, fortgesetzt.

Sie sehen den Hauptunterschied beim Vergleich der Jobcontrol-Nachrichten von bash und ksh93:

Bash- Berichte:

[1]+ Stopped sleep 1

aber ksh93 berichtet:

^Z[1] + Stopped while true; do echo .; sleep 1; done

zsh verhält sich ähnlich wie ksh93

Mit beiden Shells haben Sie einen einzelnen Prozess (die Haupt-Shell), solange Sie nicht ^ Z eingeben, und zwei Shell-Prozesse, nachdem Sie ^ Z eingegeben haben.

schily
quelle
dashWird das Signal nicht tatsächlich verarbeitet, wenn die Schleife endet? Im [d]?ashQuellcode sind alle diese Makros für INTON und INTOFF überall verteilt, und normalerweise werden Signale, die in einem INTOFF- Zustand empfangen werden, tatsächlich bei (oder um) INTON verarbeitet . Jedenfalls bin ich nur neugierig, weil ich denke, dass Sie es besser wissen - es ist eine großartige Antwort. Danke.
Mikeserv
Ich verwende Dash selten und habe es kürzlich für Leistungsvergleiche mit bash, ksh93 und meiner Bourne Shell abgerufen und kompiliert. Bei diesen Tests stellte ich fest, dass der Bindestrich hauptsächlich schnell zu sein scheint, da er keine Unterstützung für Multi-Byte-Zeichen enthält. Eine einzelne sleep 100kann angehalten und fortgesetzt werden dash, sodass sie anscheinend dashüber Probleme in diesem Befehl Bescheid weiß und die Jobsteuerung selektiv deaktiviert.
schily
In Ihren Tests konnten Sie also die dashLeistung in anderen Shells erreichen, indem Sie die Multibyte-Verarbeitung eingestellt haben? und ja, dashunterstützt die Jobsteuerung, aber der Standard besagt, dass eine interaktive Shell TSTP ignorieren sollte, und das Ausführen einer while-Schleife in der aktuellen Shell an einem interaktiven Terminal ist nicht weniger eine interaktive Shell als jede andere.
Mikeserv
Ich habe dies nicht genau getestet, aber ich konnte sehen, dass Dash zwar mehr System-CPU-Zeit verbraucht als ksh93 oder die Bourne-Shell (hauptsächlich, weil es mehr fork () -Aufrufe ausgibt), aber weniger Benutzer-CPU-Zeit benötigt und dies zu einer ähnlichen Summe führt CPU-Zeit im Vergleich zu meiner Version der Bourne Shell. Durch den Versuch, die CPU-Zeit der Benutzer in der Bourne Shell zu reduzieren, weiß ich, dass der größte Teil dieser Zeit für Multibyte-Konvertierungen aufgewendet wird.
schily
4

Ich habe einen der Mitautoren von Bash über das Thema geschrieben, und hier ist seine Antwort:

Es ist nicht wirklich ein Fehler, aber es ist sicherlich eine Einschränkung.

Die Idee dabei ist, dass Sie Prozesse anhalten, die eine andere Granularitätseinheit darstellen als Shell-Befehle. Wenn ein Prozess angehalten wird, kehrt er zur Shell zurück (mit einem Status ungleich Null, was Konsequenzen hat, wenn Sie beispielsweise einen Prozess stoppen, der der Schleifentest ist), der die Wahl hat: Er kann aus der Schleife ausbrechen oder diese fortsetzen und den gestoppten Prozess hinter sich lassen. Bash hat sich entschieden - und hat sich immer dafür entschieden - aus Schleifen auszubrechen, wenn ein Job gestoppt wird. Das Fortsetzen der Schleife ist selten das, was Sie wollen.

Einige andere Shells führen beispielsweise eine Kopie der Shell aus, wenn ein Prozess aufgrund von SIGTSTP angehalten wird, und stoppen diesen Prozess. Bash hat das noch nie getan - es scheint komplizierter zu sein als die Leistungsgarantien -, aber wenn jemand diesen Code als Patch einreichen möchte, würde ich mir überlegen, die Änderungen zu übernehmen.

Wenn also jemand einen Patch einreichen möchte, verwenden Sie die E-Mail-Adressen auf den Manpages.

Forthrin
quelle