mettere in pausa uno script bash fino al termine dei comandi precedenti

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

  • Cerca nel manuale il builtin wait.

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 utilizzare nohup 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 semplice wait tra i due for loop genererà il secondo for da eseguire solo dopo che tutti i processi figli avviati dal primo for 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 a wait:

    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 o cc1plus nel top 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 che bash attenda i processi in background che ha generato da solo, nientaltro. Potrebbe esserci un po di confusione qui: questi for 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 come while ... < 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 mostra R a volte o cc1plus.
  • In tal caso, dovrai trovare un denominatore comune, visualizzato nellelenco ps -ef. Oppure, dopo ogni comando nohup, registra il PID su una variabile (preferibilmente un array) con echo ${!} e controlla questo gruppo di PID. Quando scompaiono tutti, puoi procedere al secondo for loop

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *