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

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 

möchte ich für Der erste Satz von Jobs, der beendet werden muss, bevor der neue Satz gestartet wird. Aufgrund der nohup scheinen sie jedoch alle gleichzeitig ausgeführt zu werden.

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

Kommentare

  • Durchsuchen Sie das Handbuch nach wait.

Antwort

Sie möchten den Befehl wait verwenden, um Tun Sie dies für Sie. Sie können entweder alle untergeordneten Prozess-IDs erfassen und speziell auf sie warten. Wenn dies die einzigen Hintergrundprozesse sind, die Ihr Skript erstellt, können Sie einfach wait aufrufen Zum Beispiel:

#!/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" 

Antwort

Einige Punkte:

  • Wenn Ihr Ziel mit nohup darin besteht, zu verhindern, dass ein Remote-Shell-Exit Ihre Arbeitsprozesse beendet, sollten Sie im Skript selbst, nicht in den einzelnen Worker-Prozessen, die es erstellt.

  • Wie hier erläutert , nohup verhindert nur, dass Prozesse SIGHUP empfangen und von der Interaktion mit dem Terminal, aber es unterbricht nicht die Beziehung zwischen der Shell und ihren untergeordneten Prozessen.

  • Aufgrund des obigen Punktes mit oder ohne nohup, ein einfaches wait zwischen den beiden for Schleifen verursacht die zweite for soll erst ausgeführt werden, nachdem alle untergeordneten Prozesse, die mit dem ersten for gestartet wurden, beendet wurden.

  • Mit einem einfachen wait:

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

  • Wenn Sie die zweite for nur ausführen müssen, wenn in der ersten keine Fehler aufgetreten sind Dann müssen Sie jede Worker-PID mit $! speichern und alle an wait:

    pids= for ... worker ... & pids+=" $!" done wait $pids || { echo "there were errors" >&2; exit 1; } 

Kommentare

  • Es wären andere Jobs, die auf dem Server ausgeführt werden. Ich ' möchte also nur auf meinen Stapel warten. Es handelt sich um R-Skripte, daher werden sie unter R oder cc1plus im Befehl top
  • Außerdem möchte ich ' nohup im Inneren verwenden um alle Befehle in " parallel " auszuführen. Im Grunde sind dies Simulationen für ein wissenschaftliches Programm. Ich möchte insgesamt 180 Simulationen ausführen, aber in Stapeln von 60. Der Zähler muss auch von 1 auf 180 gehen. Wenn ich sie einzeln ausführe, dauert es zu lange.
  • wait bewirkt, dass bash auf die Hintergrundjobs wartet, die es selbst erzeugt hat, sonst nichts. Hier kann es zu Verwirrung kommen – diese for -Schleifen haben Sie in einer Datei gespeichert und als Skript aufgerufen (was ich aufgrund der line), oder tippen Sie sie manuell im Terminal ein?
  • Ich habe cat file.txt | while ausgeführt und die Pids wurden nicht außerhalb der Schleife gesetzt Der Befehl wait sah also eine leere $pids Zeichenfolge. Warum dies geschieht, wird unter serverfault.com/q/259339 erläutert. leicht zu beheben als while ... < files.txt wie beantwortet unter serverfault.com/a/259346
  • Nur neugierig Was ist der Zweck von + Zeichen mit PID-Variable?

Antwort

Verwenden Sie die fg eingebaut. Es wartet, bis die Hintergrundprozesse abgeschlossen sind.

Versuchen Sie help fg für Details.

Kommentare

  • Ein Skript wird ohne Jobsteuerung ausgeführt.

Antwort

Wenn Sie so etwas wie das folgende Codesegment einfügen Zwischen Ihren beiden for -Schleifen 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 

Natürlich, wenn Ihre Anwendung Rscript hat die Chance, nicht erfolgreich abzuschließen und zu verweilen. Ihre zweite for-Schleife hat möglicherweise keine Chance zu laufen. Das obige Codesegment geht davon aus, dass alle Prozesse mit der Kennung Rscript --vanilla abgeschlossen werden und ordnungsgemäß verschwinden. Ohne zu wissen, was Ihre Anwendung tut und wie sie ausgeführt wird, muss ich mich auf diese Annahme verlassen.

BEARBEITEN

Angesichts der Kommentare wäre dies besser geeignet Deine Bedürfnisse. (Es enthält Ihren Originalcode sowie die Logik zur Überprüfung der Fertigstellung.)

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 

Kommentare

  • Der Prozess Der Name in top zeigt manchmal entweder R oder cc1plus.
  • In diesem Fall müssen Sie einen gemeinsamen Nenner finden, der in der Liste ps -ef angezeigt wird. Oder zeichnen Sie nach jedem Befehl nohup die PID mit echo ${!} in einer Variablen (vorzugsweise einem Array) auf und suchen Sie nach dieser Gruppe von PIDs. Wenn alle verschwunden sind, können Sie mit der zweiten for -Schleife

fortfahren

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.