Ho uno script bash simile al seguente:
##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
Vorrei creare un altro ciclo for dopo il primo per continuare per altri 30. Ad esempio
##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
Vorrei per la prima serie di lavori da finire prima di iniziare la nuova serie. Ma a causa del nohup
sembra che vengano eseguiti tutti contemporaneamente.
Ho nohup
perché accedo da remoto al mio server e avvio i lavori da lì, quindi chiudo la mia bash. Esiste una soluzione alternativa?
Commenti
Risposta
Dovrai utilizzare il comando wait
per fallo per te. Puoi catturare tutti gli ID dei processi secondari e aspettarli specificatamente oppure, se sono gli unici processi in background che il tuo script sta creando, puoi semplicemente chiamare wait
senza argomenti. Ad esempio:
#!/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"
Answer
Alcuni punti:
-
Se il tuo obiettivo con
nohup
è impedire che luscita della shell remota interrompa i tuoi processi di lavoro, dovresti utilizzarenohup
sullo script stesso, non sui singoli processi di lavoro che crea. -
Come spiegato qui ,
nohup
impedisce solo ai processi di ricevere SIGHUP e dallinterazione con il terminale, ma non interrompe la relazione tra la shell ei suoi processi figli. -
A causa del punto precedente, con o senza
nohup
, un semplicewait
tra i duefor
loop genererà il secondofor
da eseguire solo dopo che tutti i processi figli avviati dal primofor
sono terminati. -
Con un semplice
wait
:si attendono tutti i processi figli attualmente attivi e lo stato di ritorno è zero.
-
Se devi eseguire il secondo
for
solo se non ci sono stati errori nel primo , quindi dovrai salvare ogni PID worker con$!
e passarli tutti await
:pids= for ... worker ... & pids+=" $!" done wait $pids || { echo "there were errors" >&2; exit 1; }
Commenti
- Là cou Ci sarebbero altri lavori in esecuzione sul server. Quindi ' desidero solo aspettare il mio batch .. sono script R, quindi vengono eseguiti in
R
occ1plus
neltop
comando - Inoltre ' vorrei usare nohup allinterno per eseguire tutti i comandi in " parallel ". fondamentalmente si tratta di simulazioni per un programma scientifico. Voglio eseguire 180 simulazioni in totale, ma in batch di 60. Anche il contatore deve andare da 1 a 180. Se le eseguo una alla volta, ci vorrà troppo tempo.
-
wait
fa in modo chebash
attenda i processi in background che ha generato da solo, nientaltro. Potrebbe esserci un po di confusione qui: questifor
loop, li hai salvati in un file e li hai richiamati come script (quello che presumo, a causa del##script
riga), o li stai digitando a mano nel terminale? - stavo facendo
cat file.txt | while
e il pid non era impostato fuori dal ciclo quindi il comando wait ha visto una stringa$pids
vuota. il motivo per cui questo accade è discusso in serverfault.com/q/259339 . facilmente risolto comewhile ... < files.txt
come risposta a serverfault.com/a/259346 - Semplicemente curioso qual è lo scopo del segno + con la variabile pids?
Risposta
Utilizza fg
incorporato. Attende il completamento dei processi in background.
Prova help fg
per i dettagli.
Commenti
- Uno script viene eseguito senza il controllo del lavoro.
Risposta
Se inserisci qualcosa di simile al seguente segmento di codice tra i tuoi due for
loop, potrebbe essere daiuto.
flag=0 while [ flag -eq 0 ] do ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null flag=${?} sleep 10 done
Ovviamente, se la tua applicazione Rscript
ha la possibilità di non completarsi correttamente e di indugiare, il tuo secondo ciclo for potrebbe non avere la possibilità di essere eseguito. Il segmento di codice precedente presuppone che tutti i processi con lidentificatore Rscript --vanilla
vengano completati e scomparsi correttamente. Senza sapere cosa fa la tua applicazione e come funziona, devo fare affidamento su questo presupposto.
EDIT
Alla luce dei commenti, questo sarebbe più adatto I tuoi bisogni. (include il codice originale e la logica di controllo del completamento)
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
Commenti
- Il processo il nome in
top
mostraR
a volte occ1plus
. - In tal caso, dovrai trovare un denominatore comune, visualizzato nellelenco
ps -ef
. Oppure, dopo ogni comandonohup
, registra il PID su una variabile (preferibilmente un array) conecho ${!}
e controlla questo gruppo di PID. Quando scompaiono tutti, puoi procedere al secondofor
loop
wait
.