pausa ett bash-skript tills tidigare kommandon är klara

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

  • Sök i manualen för wait inbyggt.

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ända nohup 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 enkel wait mellan de två for slingorna orsakar den andra for ska köras först efter att alla underordnade processer som startats av den första for 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 till wait:

    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 eller cc1plus i kommandot top
  • 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 att bash väntar på de bakgrundsjobb som det skapade själv, inget annat. Det kan finnas viss förvirring här – dessa for 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 som while ... < 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 antingen R ibland eller cc1plus.
  • I så fall måste du hitta en gemensam nämnare som visas i ps -ef -listan. Eller efter varje nohup -kommando, spela in PID till en variabel (helst en array) genom echo ${!} och kontrollera om den här gruppen av PID. När alla försvinner kan du gå vidare till den andra for loop

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *