%2C%20funktioniert%20im%20Skript%20nicht.png)
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 jobs
endet 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 jobs
nicht 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 jobs
denke 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 jobs
werden 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 jobs
hier ist also nie leer. Auch wenn der Job abgeschlossen ist, jobs
wird die Done
Meldung immer noch zurückgegeben. Deshalb hat die Lösung von Metal3d jobs -r
funktioniert.
Was noch verwirrender ist, ist, warum jobs
es 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 ping
er 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