Anhalten eines Bash-Skripts, bis die vorherigen Befehle beendet sind

20

Ich habe ein Bash-Skript, das wie folgt aussieht:

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Ich möchte eine weitere for-Schleife nach der ersten erstellen, um für weitere 30 fortzufahren. Zum Beispiel

##script
#!/bin/bash
rm data*
rm logfile*
for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done

Ich möchte, dass der erste Auftragssatz beendet wird, bevor der neue Satz gestartet wird. Aber wegen dem nohupscheint es, dass sie alle gleichzeitig laufen.

Ich habe, nohupweil ich mich remote auf meinem Server anmelde und die Jobs dort starte und dann meine Bash schließe. Gibt es eine alternative Lösung?

Masfenix
quelle
1
waitDurchsuchen Sie das Handbuch nach dem eingebauten.
Satō Katsura

Antworten:

22

Sie möchten den waitBefehl verwenden, um dies für Sie zu tun. Sie können entweder alle untergeordneten Prozess-IDs erfassen und gezielt auf sie warten, oder Sie können sie waitohne Argumente aufrufen, wenn sie die einzigen Hintergrundprozesse sind, die Ihr Skript erstellt . Beispielsweise:

#!/bin/bash
# run two processes in the background and wait for them to finish

nohup sleep 3 &
nohup sleep 10 &

echo "This will wait until both are done"
date
wait
date
echo "Done"
ParanoidGeek
quelle
6

Ein paar Punkte:

  • Wenn Sie mit nohupverhindern möchten, dass ein Remote-Shell-Exit Ihre Worker-Prozesse beendet, sollten Sie dies nohupfür das Skript selbst und nicht für die einzelnen von ihm erstellten Worker-Prozesse verwenden.

  • Wie hier erläutert , wird nohupnur verhindert , dass Prozesse SIGHUP empfangen und mit dem Terminal interagieren. Die Beziehung zwischen der Shell und ihren untergeordneten Prozessen wird jedoch nicht unterbrochen.

  • Aufgrund des obigen Punktes mit oder ohne nohupwird eine einfache waitZwischenschleife fordazu führen, dass die zweite Schleife forerst ausgeführt wird, nachdem alle untergeordneten Prozesse, die von der ersten gestartet wurden, beendet forwurden.

  • Mit einem einfachen wait:

    Es wird auf alle derzeit aktiven untergeordneten Prozesse gewartet, und der Rückgabestatus ist Null.

  • Wenn Sie die zweite fornur ausführen müssen, wenn in der ersten keine Fehler aufgetreten sind, müssen Sie jede Arbeiter-PID mit speichern $!und sie alle übergeben an wait:

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }
Matei David
quelle
Auf dem Server werden möglicherweise andere Jobs ausgeführt. Also habe ich nur für meine Charge warten wollen würde .. sie sind R - Skripte , so dass sie unter ausgeführt werden Roder cc1plusin dem topBefehl
masfenix
Außerdem möchte ich nohup inside verwenden, um alle Befehle "parallel" auszuführen. Im Grunde sind dies Simulationen für ein wissenschaftliches Programm. Ich möchte insgesamt 180 Simulationen ausführen, aber in Chargen von 60. Der Zähler muss auch von 1 auf 180 gehen. Wenn ich sie einzeln durchführe, dauert es zu lange.
Masfenix
waitbewirkt bash, dass auf die Hintergrundjobs gewartet wird, die er selbst erzeugt hat, sonst nichts. Hier könnte es zu Verwirrung kommen - diese forSchleifen, haben Sie sie in einer Datei gespeichert und als Skript aufgerufen (was ich aufgrund der ##scriptZeile angenommen habe), oder tippen Sie sie manuell im Terminal ein?
Matei David
-1

Verwenden Sie das fgeingebaute. Es wird gewartet, bis die Hintergrundprozesse beendet sind.

Versuchen Sie es help fgfür Details.

Luchostein
quelle
Ein Skript wird ohne Jobsteuerung ausgeführt.
Kusalananda
-1

Wenn Sie so etwas wie das folgende Codesegment zwischen Ihre beiden forSchleifen einfügen , kann dies hilfreich sein.

flag=0

while [ flag -eq 0 ]
do
  ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null
  flag=${?}
  sleep 10
done

Wenn Ihre Anwendung Rscriptmöglicherweise nicht erfolgreich abgeschlossen wird und nicht lange ausgeführt wird, hat Ihre zweite for-Schleife möglicherweise keine Chance, ausgeführt zu werden. Das obige Codesegment geht davon aus, dass alle Prozesse mit dem Bezeichner Rscript --vanillaordnungsgemäß abgeschlossen werden und verschwinden. Ohne zu wissen, was Ihre Anwendung macht und wie sie läuft, muss ich mich auf diese Annahme verlassen.

BEARBEITEN

In Anbetracht der Kommentare würde dies Ihren Bedürfnissen besser entsprechen. (Es enthält Ihren Originalcode sowie die Logik für die Abschlussprüfung.)

for i in {1..30}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
pids[$i]=${!}
done

flag=0

while [ flag -eq 0 ] 
do
  for PID in $(echo ${pids[@]})
  do
    flag=1
    ps -ef | grep ${PID} | grep -v grep >/dev/null; r=${?}
    if [ ${r} -eq 0 ]
    then 
      flag=0
    fi
  done
done

for i in {31..60}
do
## append a & if you want to run it parallel;
nohup Rscript --vanilla main.R 10 100 $i &> logfile"$i" &
done
MelBurslan
quelle
Der Prozessname in topwird entweder Rmanchmal oder angezeigt cc1plus.
Masfenix
In diesem Fall müssen Sie einen gemeinsamen Nenner finden, der in der ps -efListe angezeigt wird. Oder nohupzeichnen Sie nach jedem Befehl die PID in einer Variablen (vorzugsweise einem Array) auf echo ${!}und suchen Sie nach dieser Gruppe von PIDs. Wenn sie alle verschwinden, können Sie in die zweite gehen forSchleife
MelBurslan