Jag har ett bash-skript som ser ut som följande:
##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
Jag vill skapa en annan för loop efter den första för att fortsätta för ytterligare 30. Till exempel
##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
Jag skulle vilja för den första uppsättningen jobb som ska avslutas innan den nya uppsättningen startas. Men på grund av nohup
verkar det som om de alla körs samtidigt.
Jag har nohup
eftersom jag fjärrloggar in på min server och startar jobben där och stänger sedan min bash. Finns det en alternativ lösning?
Kommentarer
Svar
Du vill använda kommandot wait
för att gör det åt dig. Du kan antingen fånga alla barn behandla ID och vänta på dem specifikt, eller om det är de enda bakgrundsprocesser som ditt skript skapar, kan du bara ringa wait
utan argument. Till exempel:
#!/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"
Svar
Några punkter:
-
Om ditt mål med
nohup
är att förhindra att en fjärrskalutgång dödar dina arbetstagares processer, bör du användanohup
på själva skriptet, inte på de enskilda arbetarens processer som det skapar. -
Som förklaras här ,
nohup
hindrar endast processer från att ta emot SIGHUP och från att interagera med terminalen, men det bryter inte förhållandet mellan skalet och dess underprocesser. -
På grund av punkten ovan, med eller utan
nohup
, en enkelwait
mellan de tvåfor
slingorna orsakar den andrafor
ska köras först efter att alla underordnade processer som startats av den förstafor
har avslutats. -
Med en enkel
wait
:alla för närvarande aktiva underordnade processer väntar på och returstatusen är noll.
-
Om du behöver köra den andra
for
bara om det inte fanns några fel i det första , då måste du spara varje arbetares PID med$!
och skicka dem alla tillwait
:pids= for ... worker ... & pids+=" $!" done wait $pids || { echo "there were errors" >&2; exit 1; }
Kommentarer
- Det finns Det skulle vara andra jobb som körs på servern. Så jag ' vill bara vänta på mitt parti .. de är R-skript så de körs under
R
ellercc1plus
i kommandottop
- Jag vill också ' använda nohup inuti att köra alla kommandon i " parallellt ". i grund och botten är detta simuleringar för ett vetenskapligt program. Jag vill köra 180 simuleringar totalt, men i satser på 60. Räknaren måste också gå från 1 till 180. Om jag gör dem en i taget tar det för lång tid.
-
wait
gör attbash
väntar på de bakgrundsjobb som det skapade själv, inget annat. Det kan finnas viss förvirring här – dessafor
loopar, sparade du dem i en fil och åberopade dem som ett skript (vad jag antog på grund av##script
-raden), eller skriver du dem för hand i terminalen? - Jag gjorde
cat file.txt | while
och pidsen sattes inte utanför slingan så vänta kommandot såg en tom$pids
sträng. varför detta händer diskuteras på serverfault.com/q/259339 . enkelt fixas somwhile ... < files.txt
som svarat på serverfault.com/a/259346 - Bara nyfiken vad är syftet med + -tecknet med pids-variabel?
Svar
Använd fg
inbyggd. Det väntar tills bakgrundsprocesserna är slut.
Försök med help fg
.
Kommentarer
- Ett skript körs utan jobbkontroll.
Svar
Om du infogar något som följande kodsegment mellan dina två for
loopar kan det hjälpa.
flag=0 while [ flag -eq 0 ] do ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null flag=${?} sleep 10 done
Naturligtvis, om din ansökan Rscript
har en chans att inte slutföra framgångsrikt och dröja kvar, din andra för loop kanske inte har en chans att springa. Kodsegmentet ovan förutsätter att alla processer med identifieraren Rscript --vanilla
kommer att slutföras och försvinna ordentligt. Utan att veta vad din ansökan gör och hur den kör, måste jag förlita mig på detta antagande.
EDIT
Mot bakgrund av kommentarerna skulle detta bättre passa dina behov. (den innehåller din ursprungliga kod samt logik för kompletteringskontroll)
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
Kommentarer
- Processen namn i
top
visar antingenR
ibland ellercc1plus
. - I så fall måste du hitta en gemensam nämnare som visas i
ps -ef
-listan. Eller efter varjenohup
-kommando, spela in PID till en variabel (helst en array) genomecho ${!}
och kontrollera om den här gruppen av PID. När alla försvinner kan du gå vidare till den andrafor
loop
wait
inbyggt.