So erhalten Sie eine Liste aller untergeordneten Prozesse, die von einem Skript erzeugt wurden

9

Kontext:

Benutzer stellen mir ihre benutzerdefinierten Skripte zur Ausführung zur Verfügung. Diese Skripte können beliebig ähnlich sein wie Skripte zum Starten mehrerer GUI-Programme und Backend-Dienste. Ich habe keine Kontrolle darüber, wie die Skripte geschrieben werden. Diese Skripte können blockierend sein, dh die Ausführung wartet, bis alle untergeordneten Prozesse (Programme, die nacheinander ausgeführt werden) beendet werden

#exaple of blocking script
echo "START"
first_program 
second_program 
echo "DONE"

oder nicht blockierender Typ, dh solche, die untergeordnete Prozesse im Hintergrund abspalten und so etwas wie beenden

#example of non-blocking script
echo "START"
first_program &
second_program &
echo "DONE"

Was versuche ich zu erreichen?

Vom Benutzer bereitgestellte Skripte können von einem der beiden oben genannten Typen oder einer Mischung aus beiden sein. Meine Aufgabe ist es, das Skript auszuführen und zu warten, bis alle von ihm gestarteten Prozesse beendet sind, und dann den Knoten herunterzufahren. Wenn es sich um einen blockierenden Typ handelt, ist der Fall ganz einfach, dh Sie erhalten die PID des Skriptausführungsprozesses und warten, bis ps -ef | grep -ef PID keine Einträge mehr hat. Nicht blockierende Skripte bereiten mir Probleme

Gibt es eine Möglichkeit, eine Liste der PIDs aller untergeordneten Prozesse abzurufen, die durch die Ausführung eines Skripts erzeugt wurden? Alle Hinweise oder Hinweise werden sehr geschätzt

irraju
quelle
Ich glaube nicht, dass dies nach dem Ende des übergeordneten Skripts möglich ist, es sei denn, Sie können die PID des übergeordneten Skripts erfassen. Wenn Sie die Skripte starten, können Sie sie in etwas einschließen, pid$(foo.sh; echo $!)das Ihnen die PID von gibt, foo.shdamit Sie sie dann verwenden können ps --ppid. Wird es funktionieren?
Terdon
2
Müssen die Skripte unter der UID des Autorenbenutzers ausgeführt werden? Wenn nicht, können Sie einen Dummy-Benutzer nur für diesen Zweck erstellen? Sie würden nicht einmal brauchen grep, nur ps –udummy_user. Schauen Sie sich auch Prozessgruppen an.
Scott
Dies ist eher eine Art Problemumgehung als eine Lösung für Ihre erste Frage: Öffnen Sie eine neue Bash-Sitzung. Sie können alle aus dieser Shell hervorgerufenen Prozesse psohne Argumente auflisten (sollte nur bashund psam Anfang sein). Starten Sie dort Ihr Skript. Warten Sie danach, bis ps | wc -lder erwartete Wert erreicht ist.
Tim

Antworten:

8

Um Ihre Frage direkt zu beantworten, klicken Sie auf den Befehl

jobs -p

gibt Ihnen die Liste aller untergeordneten Prozesse.

Alternative Nr. 1

In Ihrem Fall ist es jedoch möglicherweise einfacher, den Befehl waitohne Parameter zu verwenden:

first_program &
second_program &
wait

Dies wartet, bis ALLE untergeordneten Prozesse abgeschlossen sind.

Alternative Nr. 2

Eine andere Alternative besteht $!darin, die PID des letzten Programms abzurufen und möglicherweise in einer Variablen zu akkumulieren, wie folgt :

pids=""
first_program &
pids="$pids $!"
second_program &
pids="$pids $!"

und verwenden Sie dann wait damit (dies ist der Fall, wenn Sie nur auf eine Teilmenge Ihrer untergeordneten Prozesse warten möchten):

wait $pids

Alternative Nr. 3

Oder, wenn Sie nur warten, bis ANY Prozess abgeschlossen ist, können Sie

wait -n $pids

Bonusinfo

Wenn Sie möchten, dass ein Sigterm in Ihrem Bash-Skript auch Ihre untergeordneten Prozesse schließt, müssen Sie das Signal mit so etwas weitergeben (setzen Sie dies irgendwo oben, bevor Sie einen Prozess starten):

trap 'kill $(jobs -p)' SIGINT SIGTERM EXIT
Vlad A Ionescu
quelle
1

Vielen Dank für Ihre Antworten. Ich habe die Lösung für Stackoverflow erhalten

Mit wait können Sie warten, bis alle von Userscript gestarteten Hintergrundprozesse abgeschlossen sind. Da wait nur für untergeordnete Elemente der aktuellen Shell funktioniert, müssen Sie deren Skript als Quellcode ausführen, anstatt es als separaten Prozess auszuführen.

(Quellbenutzerskript; warten)

Die Beschaffung des Skripts in einer expliziten Unterschale sollte das Starten eines neuen Prozesses genau genug simulieren. Wenn nicht, können Sie auch die Unterschale im Hintergrund speichern, wodurch ein neuer Prozess gestartet wird, und dann warten, bis er abgeschlossen ist.

(Quellbenutzerskript; warten) & warten

Hier ist der Link für die ursprüngliche Antwort von @chepner: /programming/18663196/how-to-get-list-of-all-child-process-spawned-by-a-script/18663969?noredirect = 1 # 18663969

irraju
quelle
3
Ich habe auch darüber nachgedacht, aber diese Lösung schlägt fehl, wenn Userscript einen Index im Hintergrund startet, der dann ein anderes Skript im Hintergrund startet. Ihr waitBefehl wartet dann auf die Kinder von Userscript , nicht jedoch auf seine Enkelkinder.
Tim
@ Tim Gerade realisiert, dass :(
irraju