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 utilizzarenohupsullo script stesso, non sui singoli processi di lavoro che crea. -
Come spiegato qui ,
nohupimpedisce 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 semplicewaittra i dueforloop genererà il secondoforda eseguire solo dopo che tutti i processi figli avviati dal primoforsono terminati. -
Con un semplice
wait:si attendono tutti i processi figli attualmente attivi e lo stato di ritorno è zero.
-
Se devi eseguire il secondo
forsolo 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
Rocc1plusneltopcomando - 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.
-
waitfa in modo chebashattenda i processi in background che ha generato da solo, nientaltro. Potrebbe esserci un po di confusione qui: questiforloop, li hai salvati in un file e li hai richiamati come script (quello che presumo, a causa del##scriptriga), o li stai digitando a mano nel terminale? - stavo facendo
cat file.txt | whilee il pid non era impostato fuori dal ciclo quindi il comando wait ha visto una stringa$pidsvuota. il motivo per cui questo accade è discusso in serverfault.com/q/259339 . facilmente risolto comewhile ... < files.txtcome 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
topmostraRa 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 secondoforloop
wait.