Ausführen mehrerer Programme im Hintergrund und Überprüfen ihres Rückgabewerts

Ausführen mehrerer Programme im Hintergrund und Überprüfen ihres Rückgabewerts

Angenommen, ich möchte ein paar (sagen wir drei) Programme gleichzeitig ausführen, wie folgt

program1 & program2 & program3 &

Wenn ich ihre wissen will pid's, denke ich, dass der beste Weg ist, sie zu speichern, so

program1 &
pid1=$!
program2 &
pid2=$!
...

Was aber, wenn ich nun wissen möchte, ob sie beendet sind und wenn ja, welchen Wert sie zurückgegeben haben? Etwa so:

if [ program1 has ended ]; then
    do something with its return value
fi

Jede Hilfe wird geschätzt

Antwort1

# launch child process in background
launch_child_process &

# grab child's pid and store it (use array if several)
pid=$!

# later, wait for termination
wait $pid
# show return code from wait, which is actually the return code of the child
echo "Child return code:" $?

Bei mehreren untergeordneten Elementen können Sie natürlich eine Schleife ausführen, um auf jedes PID zu warten und den entsprechenden Rückgabecode abzurufen. Sie verlassen diese Schleife, wenn das letzte untergeordnete Element beendet ist.

Antwort2

Eine einfache Lösung besteht darin, eine Nachricht in eine Protokolldatei zu schreiben

Sagen wir, für Programm 1 machen Sie etwas wie:

#!/bin/bash
.
.
your stuff
.
.
end_time==$(date)
echo "program1 ended at $end_time" > program1_log

Eine andere Lösung wäre, eine leere Datei zu erstellen, um das Prozessende zu markieren.

#!/bin/bash
.
.
your stuff
.
.
echo $? > /some/path/program1_ended #storing the exit value
#disadvantage is that you can't verify if intermediate commands failed.

Dann überprüfen Sie

   if [ -e /some/path/program1_ended ]
   then
   exit_status=$( </some/path/program1_ended )
   rm /some/path/program1_ended #Deleting the file, getting ready for next run
   .
   .
   Do something
   else
   echo "program1 has not ended yet"
  fi

Antwort3

POSIX sh ist nicht sehr gut im Umgang mit mehreren Hintergrundprozessen. Das grundlegende Tool ist das waiteingebaute, das blockiert, bis ein Hintergrundprozess beendet wird. Aber waitohne Argument wartet es, bisalleHintergrundprozesse wurden beendet und gibt den Beendigungsstatus des letzten Prozesses zurück, der beendet wurde; der Beendigungsstatus der anderen Unterprozesse geht verloren.

Sie können eine Falle für SIGCHLD setzen, das Signal, das ausgelöst wird, wenn ein untergeordneter Prozess beendet wird. Dadurch wird Code ausgeführt, wenn ein Unterprozess beendet wird. Sie erfahren jedoch nicht unbedingt, welcher Unterprozess beendet wurde oder welchen Rückgabestatus er hat. Verschiedene Shells verhalten sich unterschiedlich.

ATT ksh93 (nicht mksh oder pdksh!) ist die einzige unter den gängigen Shells, die sich bei SIGCHLD-Traps sinnvoll verhält. Sie setzt $!auf die PID des beendeten Prozesses und $?auf dessen Rückgabestatus.

#!/bin/ksh
trap 'Process $! (${subprocesses[$!]}) exited with status $?' CHLD
typeset -A subprocesses
program1 & subprocesses[$!]='program1'
program2 & subprocesses[$!]='program2'
wait

Wenn Sie eine andere Shell verwenden, führen Sie alle Nachbehandlungen im Unterprozess durch.

#!/bin/sh
{ program1; echo "program1 exited with status $?"; } &
{ program2; echo "program2 exited with status $?"; } &
wait

Oder verwenden Sie eine leistungsfähigere Sprache wie Perl, Python, Ruby usw.

Antwort4

Wenn Sie ungefähr wissen, in welcher Reihenfolge die Prozesse enden, können Sie wait <pid>auf die Beendigung warten. Der waitBefehl übernimmt dann den Beendigungsstatus des Prozesses, auf den gewartet wurde. Beispiel:

if wait $pid1
then echo "$pid1 was ok"
else echo "$pid1 failed with code $?"
fi

Wenn Sie die Reihenfolge nicht kennen, können Sie mit auf einen beliebigen von ihnen warten wait -n $pid1 $pid2 ...und den Exit-Code auf ähnliche Weise erhalten. Sie erfahren dann jedoch nicht, welcher Prozess beendet wurde. Dies ist jedoch nützlich, wenn Sie nur wissen müssen, ob einer fehlgeschlagen ist.

verwandte Informationen