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 einfacheswait
zwischen den beidenfor
Schleifen verursacht die zweitefor
soll erst ausgeführt werden, nachdem alle untergeordneten Prozesse, die mit dem erstenfor
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 anwait
: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
odercc1plus
im Befehltop
- 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, dassbash
auf die Hintergrundjobs wartet, die es selbst erzeugt hat, sonst nichts. Hier kann es zu Verwirrung kommen – diesefor
-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 alswhile ... < 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 entwederR
odercc1plus
. - In diesem Fall müssen Sie einen gemeinsamen Nenner finden, der in der Liste
ps -ef
angezeigt wird. Oder zeichnen Sie nach jedem Befehlnohup
die PID mitecho ${!}
in einer Variablen (vorzugsweise einem Array) auf und suchen Sie nach dieser Gruppe von PIDs. Wenn alle verschwunden sind, können Sie mit der zweitenfor
-Schleife
fortfahren