Dies ist eine Erweiterung von die am häufigsten gewählte Antwort, von @Luca Tettamanti , um eine voll funktionsfähig Beispiel.
Diese Antwort hat mich stutzig gemacht :
Welcher Typ von Variable ist n_procs
und was enthält es? Welcher Typ von Variable ist procs
und was enthält sie? Kann bitte jemand diese Antwort aktualisieren, um sie lauffähig zu machen, indem er Definitionen für diese Variablen hinzufügt? Ich verstehe nicht, wie.
...und auch:
- Wie erhalten Sie den Rückgabecode vom Unterprozess, wenn er abgeschlossen ist (was der Kernpunkt dieser Frage ist)?
Wie auch immer, ich habe es herausgefunden, also hier ist ein voll funktionsfähig Beispiel.
Anmerkungen:
$!
es wie man die PID (Prozess-ID) des zuletzt ausgeführten Unterprozesses erhält .
- Die Ausführung eines beliebigen Befehls mit der
&
danach, wie cmd &
zum Beispiel bewirkt, dass er im Hintergrund als paralleler Suprozess zum Hauptprozess läuft.
myarray=()
ist, wie man ein Array in der Bash erstellt.
- Um ein wenig mehr über die
wait
eingebauter Befehl, siehe help wait
. Siehe auch und insbesondere die offizielles Bash-Benutzerhandbuch auf Job Control built-ins, wie zum Beispiel wait
y jobs
, hier: https://www.gnu.org/software/bash/manual/html_node/Job-Control-Builtins.html#index-wait .
Vollständiges, lauffähiges Programm: Warten auf das Ende aller Prozesse
multi_process_program.sh (aus meinem eRCaGuy_hello_world repo):
#!/usr/bin/env bash
# This is a special sleep function which returns the number of seconds slept as
# the "error code" or return code" so that we can easily see that we are in
# fact actually obtaining the return code of each process as it finishes.
my_sleep() {
seconds_to_sleep="$1"
sleep "$seconds_to_sleep"
return "$seconds_to_sleep"
}
# Create an array of whatever commands you want to run as subprocesses
procs=() # bash array
procs+=("my_sleep 5")
procs+=("my_sleep 2")
procs+=("my_sleep 3")
procs+=("my_sleep 4")
num_procs=${#procs[@]} # number of processes
echo "num_procs = $num_procs"
# run commands as subprocesses and store pids in an array
pids=() # bash array
for (( i=0; i<"$num_procs"; i++ )); do
echo "cmd = ${procs[$i]}"
${procs[$i]} & # run the cmd as a subprocess
# store pid of last subprocess started; see:
# https://unix.stackexchange.com/a/30371/114401
pids+=("$!")
echo " pid = ${pids[$i]}"
done
# OPTION 1 (comment this option out if using Option 2 below): wait for all pids
for pid in "${pids[@]}"; do
wait "$pid"
return_code="$?"
echo "PID = $pid; return_code = $return_code"
done
echo "All $num_procs processes have ended."
Ändern Sie die obige Datei so, dass sie ausführbar ist, indem Sie chmod +x multi_process_program.sh
und führen Sie es wie folgt aus:
time ./multi_process_program.sh
Beispielhafte Ausgabe. Sehen Sie, wie die Ausgabe des time
Befehl im Aufruf zeigt, dass die Ausführung 5,084 Sekunden dauerte. Wir konnten auch erfolgreich den Rückgabecode von jedem Unterprozess abrufen.
eRCaGuy_hello_world/bash$ time ./multi_process_program.sh
num_procs = 4
cmd = my_sleep 5
pid = 21694
cmd = my_sleep 2
pid = 21695
cmd = my_sleep 3
pid = 21697
cmd = my_sleep 4
pid = 21699
PID = 21694; return_code = 5
PID = 21695; return_code = 2
PID = 21697; return_code = 3
PID = 21699; return_code = 4
All 4 processes have ended.
PID 21694 is done; return_code = 5; 3 PIDs remaining.
PID 21695 is done; return_code = 2; 2 PIDs remaining.
PID 21697 is done; return_code = 3; 1 PIDs remaining.
PID 21699 is done; return_code = 4; 0 PIDs remaining.
real 0m5.084s
user 0m0.025s
sys 0m0.061s
Weiter gehen: live bestimmen, wann jeder einzelne Prozess endet
Wenn Sie eine Aktion ausführen möchten, sobald ein Prozess beendet ist, und Sie nicht wissen, wann er beendet sein wird, können Sie eine unendliche Umfrage durchführen while
Schleife, um zu sehen, wann jeder Prozess beendet ist, und dann die gewünschte Aktion durchführen.
Kommentieren Sie einfach den obigen Codeblock "OPTION 1" aus und ersetzen Sie ihn stattdessen durch diesen Block "OPTION 2":
# OR OPTION 2 (comment out Option 1 above if using Option 2): poll to detect
# when each process terminates, and print out when each process finishes!
while true; do
for i in "${!pids[@]}"; do
pid="${pids[$i]}"
# echo "pid = $pid" # debugging
# See if PID is still running; see my answer here:
# https://stackoverflow.com/a/71134379/4561887
ps --pid "$pid" > /dev/null
if [ "$?" -ne 0 ]; then
# PID doesn't exist anymore, meaning it terminated
# 1st, read its return code
wait "$pid"
return_code="$?"
# 2nd, remove this PID from the `pids` array by `unset`ting the
# element at this index; NB: due to how bash arrays work, this does
# NOT actually remove this element from the array. Rather, it
# removes its index from the `"${!pids[@]}"` list of indices,
# adjusts the array count(`"${#pids[@]}"`) accordingly, and it sets
# the value at this index to either a null value of some sort, or
# an empty string (I'm not exactly sure).
unset "pids[$i]"
num_pids="${#pids[@]}"
echo "PID $pid is done; return_code = $return_code;" \
"$num_pids PIDs remaining."
fi
done
# exit the while loop if the `pids` array is empty
if [ "${#pids[@]}" -eq 0 ]; then
break
fi
# Do some small sleep here to keep your polling loop from sucking up
# 100% of one of your CPUs unnecessarily. Sleeping allows other processes
# to run during this time.
sleep 0.1
done
Beispiellauf und Ausgabe des vollständigen Programms mit auskommentierter Option 1 und verwendeter Option 2:
eRCaGuy_hello_world/bash$ ./multi_process_program.sh
num_procs = 4
cmd = my_sleep 5
pid = 22275
cmd = my_sleep 2
pid = 22276
cmd = my_sleep 3
pid = 22277
cmd = my_sleep 4
pid = 22280
PID 22276 is done; return_code = 2; 3 PIDs remaining.
PID 22277 is done; return_code = 3; 2 PIDs remaining.
PID 22280 is done; return_code = 4; 1 PIDs remaining.
PID 22275 is done; return_code = 5; 0 PIDs remaining.
Jede dieser PID XXXXX is done
Zeilen direkt nach Beendigung des Prozesses live ausgibt! Beachten Sie, dass, obwohl der Prozess für sleep 5
(PID 22275
in diesem Fall) zuerst ausgeführt wurde, wurde er zuletzt beendet, und wir haben jeden Prozess direkt nach seiner Beendigung erfolgreich erkannt. Wir haben auch jeden Rückgabecode erfolgreich erkannt, genau wie bei Option 1.
Andere Referenzen:
-
*****+ [SEHR HILFREICH] Exit-Code eines Hintergrundprozesses abrufen - diese Antwort lehrte mich das Schlüsselprinzip, dass (Hervorhebung hinzugefügt):
wait <n>
wartet, bis der Prozess mit der PID abgeschlossen ist (es wird blockiert, bis der Prozess abgeschlossen ist, Sie sollten diese Funktion also erst dann aufrufen, wenn Sie sicher sind, dass der Prozess abgeschlossen ist. ), und gibt dann den Exit-Code des abgeschlossenen Prozesses zurück.
Mit anderen Worten: Es half mir zu wissen, dass auch nach Abschluss des Prozesses können Sie immer noch die wait
auf, um den Rückgabecode zu erhalten!
-
So prüfen Sie, ob eine Prozess-ID (PID) existiert
- meine Antwort
-
Ein Element aus einem Bash-Array entfernen - Beachten Sie, dass Elemente in einem Bash-Array nicht wirklich gelöscht werden, sie werden nur "entschärft". Siehe meine Kommentare im obigen Code, was das bedeutet.
-
Verwendung der ausführbaren Befehlszeile true
um eine unendliche while-Schleife in der Bash zu erzeugen: https://www.cyberciti.biz/faq/bash-infinite-loop/
2 Stimmen
Dies könnte erheblich verbessert werden, um auf folgende Punkte einzugehen
wait -n
die in der modernen Bash verfügbar ist, um nur zurückzukehren, wenn der erste/nächste Befehl abgeschlossen ist.0 Stimmen
Wenn Sie mit der Bash testen wollen, versuchen Sie dies: github.com/sstephenson/bats
3 Stimmen
Die aktive Entwicklung von BATS hat sich auf github.com/bats-core/bats-core
3 Stimmen
@CharlesDuffy
wait -n
hat ein kleines Problem: Wenn keine Child-Jobs mehr übrig sind (auch bekannt als Race Condition), wird ein Exit-Status ungleich Null (fail) zurückgegeben, der von einem fehlgeschlagenen Child-Prozess nicht zu unterscheiden ist.0 Stimmen
@drevicko : warten -n Lösung hier: stackoverflow.com/a/59723887/627042
0 Stimmen
Ich habe das in einem Skript gesehen, vielleicht ist es das Richtige. sehr prägnant.
wait < <(jobs -p)
0 Stimmen
Siehe auch: Unix und Linux: Starten Sie einen Hintergrundprozess und prüfen Sie, wann er endet
0 Stimmen
Siehe auch: Exit-Code eines Hintergrundprozesses abrufen