Jeg har et bash-skript som ser slik ut:
##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
Jeg vil lage en annen for loop etter den første for å fortsette for en annen 30. For eksempel
##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
Jeg ønsker for det første settet med jobber som er ferdig før du starter det nye settet. Men på grunn av nohup
ser det ut til at de alle kjøres samtidig.
Jeg har nohup
fordi jeg logger på serveren min eksternt og starter jobbene der og lukker deretter bash. Finnes det en alternativ løsning?
Kommentarer
Svar
Du vil bruke kommandoen wait
til gjør dette for deg. Du kan enten fange alle barna behandle ID-er og vente på dem spesifikt, eller hvis det er de eneste bakgrunnsprosessene skriptet ditt oppretter, kan du bare ringe wait
uten argument. For eksempel:
#!/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
Noen få punkter:
-
Hvis målet ditt med
nohup
er å forhindre at en ekstern skallutgang dreper arbeidsprosessene dine, bør du brukenohup
på selve skriptet, ikke på de individuelle arbeidsprosessene det oppretter. -
Som forklart her ,
nohup
hindrer bare prosesser i å motta SIGHUP og fra å samhandle med terminalen, men det bryter ikke forholdet mellom skallet og dets barneprosesser. -
På grunn av punktet ovenfor, med eller uten
nohup
, en enkelwait
mellom de tofor
løkkene vil føre til at den andrefor
skal bare utføres etter at alle underordnede prosesser startet av den førstefor
er avsluttet. -
Med en enkel
wait
:alle nåværende aktive underordnede prosesser ventes, og returstatusen er null.
-
Hvis du trenger å kjøre den andre
for
bare hvis det ikke var noen feil i den første , så må du lagre hver arbeider PID med$!
, og sende dem alle tilwait
:pids= for ... worker ... & pids+=" $!" done wait $pids || { echo "there were errors" >&2; exit 1; }
Kommentarer
- Der cou Det ville være andre jobber som kjører på serveren. Så jeg ' vil bare vente på batchen min .. de er R-skript så de kjøres under
R
ellercc1plus
itop
-kommandoen - Også jeg ' vil bruke nohup inni å kjøre alle kommandoene i " parallelt ". i utgangspunktet er dette simuleringer for et vitenskapelig program. Jeg vil kjøre 180 simuleringer totalt, men i batcher på 60. Telleren må også gå fra 1 til 180. Hvis jeg gjør dem om gangen, vil det ta for lang tid.
-
wait
fårbash
til å vente på bakgrunnsjobbene det skapte selv, ingenting annet. Det kan være forvirring her – dissefor
sløyfene, lagret du dem i en fil og påkalte dem som et skript (det jeg antok på grunn av##script
linje), eller skriver du dem for hånd i terminalen? - Jeg gjorde
cat file.txt | while
og pidsene ble ikke satt utenfor løkken så ventekommandoen så en tom$pids
streng. hvorfor dette skjer blir diskutert på serverfault.com/q/259339 . lett fikset somwhile ... < files.txt
som svaret på serverfault.com/a/259346 - Bare nysgjerrig hva er hensikten med + tegn med pids-variabel?
Svar
Bruk fg
innebygd. Den venter til bakgrunnsprosesser er ferdig.
Prøv help fg
for detaljer.
Kommentarer
- Et skript kjører uten jobbkontroll.
Svar
Hvis du setter inn noe som følgende kodesegment mellom de to for
sløyfene, kan det hjelpe.
flag=0 while [ flag -eq 0 ] do ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null flag=${?} sleep 10 done
Selvfølgelig, hvis søknaden din Rscript
har en sjanse til å ikke fullføre vellykket og dvele rundt, din andre for loop har kanskje ikke sjansen til å løpe. Kodesegmentet ovenfor forutsetter at alle prosesser med identifikatoren Rscript --vanilla
vil fullføres og forsvinne ordentlig. Uten å vite hva søknaden din gjør og hvordan den kjører, må jeg stole på denne antagelsen.
REDIGER
I lys av kommentarene vil dette bedre passe dine behov. (den inkluderer den opprinnelige koden samt logikk for fullføringskontroll)
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
- Prosessen navn i
top
viser entenR
noen ganger ellercc1plus
. - I så fall må du finne en fellesnevner som vises i
ps -ef
-listen. Eller registrer PID til en variabel (helst en matrise) etter hvernohup
-kommando vedecho ${!}
og se etter denne gruppen av PIDer. Når alle forsvinner, kan du gå videre til den andrefor
loop
wait
innebygd.