Schleife, bis der Hintergrundprozess abgeschlossen ist (mit „Jobs“), funktioniert im Skript nicht

Schleife, bis der Hintergrundprozess abgeschlossen ist (mit „Jobs“), funktioniert im Skript nicht

Ich versuche, eine Schleife zu erstellen, bis ein Hintergrundprozess (der zuvor im Skript gestartet wurde) abgeschlossen ist. Ein leicht reproduzierbarer Testfall ist:

ping -c 10 localhost &>/dev/null &

Auf der Befehlszeile kann ich eine Schleife ausführen while [[ -n $(jobs) ]](während $(jobs)es nicht null ist).

$ ping -c 10 localhost &>/dev/null &
[1] 19078
$ while [[ -n $(jobs) ]]; do echo -n .; sleep 1; done
.........[1]+  Done                    ping -c 5 localhost &> /dev/null

Dieselben beiden Zeilen in einem Skript drucken jedoch weiterhin .s, bis ich drücke Ctrl-C.

Merkwürdigerweise jobsendet das Skript wie erwartet, wenn ich es innerhalb der Schleife aufrufe.

$ ./background-ping.sh
.[1]+  Running                 ping -c 5 localhost &> /dev/null &
.[1]+  Running                 ping -c 5 localhost &> /dev/null &
.[1]+  Running                 ping -c 5 localhost &> /dev/null &
.[1]+  Running                 ping -c 5 localhost &> /dev/null &
.[1]+  Done                    ping -c 5 localhost &> /dev/null

Mir ist bewusst, dass es andere Möglichkeiten gibt, zu prüfen, ob der Hintergrundjob abgeschlossen ist (z. B. durch Prüfen /proc), aber ich möchte wissen, warum die Prüfung jobsnicht wie erwartet funktioniert.

Antwort1

Wenn ich Ihr Problem richtig verstehe, werden Ihre beiden Zeilen in einem Skript nicht beendet.

Das habe ich in meinem gemacht:

ping -c 5 google.com &>/dev/null &
while [[ -n $(jobs -r) ]]; do echo -n "."; sleep 1; done

jobs -rüberprüft laufende Prozesse und der Aufruf meines Skripts funktioniert wie erwartet. Das Skript wird gestoppt, wenn der Ping abgeschlossen ist.

EDIT: Ich denke, dass in einem Skript der übergeordnete Prozess als laufender Prozess bekannt ist, und deshalb jobsdenke ich weiterhin, dass es einen laufenden Prozess gibt. Das ist eine Hypothese

Ist das die Antwort? (Oder vielleicht verstehe ich wirklich nicht, was Sie meinen. Das Problem kann mein schlechtes Englisch sein ...)

Antwort2

Wenn Sie Probleme dieser Art haben, sollten Sie immer versuchen, Ihre Variablen auszudrucken, damit Sie verstehen, was vor sich geht. In diesem Fall jobswerden auch abgeschlossene Aufträge zurückgegeben. Wenn Sie Folgendes ausführen:

ping -c 5 localhost &>/dev/null &
while [[ -n $(jobs | tee -a temp) ]]; do
    echo -n .; 
    sleep 1; 
done

Sie sehen die folgende Ausgabe in temp:

[1]+  Running                 ping -c 5 localhost &> /dev/null &
[1]+  Running                 ping -c 5 localhost &> /dev/null &
[1]+  Running                 ping -c 5 localhost &> /dev/null &
[1]+  Running                 ping -c 5 localhost &> /dev/null &
[1]+  Done                    ping -c 5 localhost &> /dev/null
[1]+  Done                    ping -c 5 localhost &> /dev/null
[1]+  Done                    ping -c 5 localhost &> /dev/null
[1]+  Done                    ping -c 5 localhost &> /dev/null
[1]+  Done                    ping -c 5 localhost &> /dev/null
[...]

Die Ausgabe jobshier ist also nie leer. Auch wenn der Job abgeschlossen ist, jobswird die DoneMeldung immer noch zurückgegeben. Deshalb hat die Lösung von Metal3d jobs -rfunktioniert.

Was noch verwirrender ist, ist, warum jobses richtig funktioniert, wenn es innerhalb der Schleife ausgeführt wird. Die Antwort wird etwas damit zu tun haben, dass es in einer separaten Subshell while [[ -n $(jobs) ]]ausgeführt wird jobs, aber ich bin mir über die Details nicht sicher. Ich habehat eine Frage gepostetdarüber auf U&L, falls jemand interessiert ist.

Antwort3

Sie können einen Befehl verwenden wait, der darauf wartet, dass Hintergrundjobs gestoppt werden

Beispiel:

$ ping -c 10 localhost &>/dev/null &
[29787]
$ wait
[1]+  Done ping -c 10 localhost &>/dev/null

Der Wartebefehl wird blockiert und wenn pinger abgeschlossen ist, wird die Eingabeaufforderung freigegeben und eine Nachricht gedruckt.

Sie können es mit mehreren Befehlen verwenden:

$ ping -c 5 localhost &>/dev/null & ping -c 5 facebook.com  &>/dev/null &
[1] 29867
[2] 29868
$ wait
[1]-  Done                    ping -c 5 localhost &>/dev/null
[2]+  Done                    ping -c 5 facebook.com &>/dev/null

verwandte Informationen