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


20

Ho uno script bash che assomiglia 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 crearne un altro per il ciclo 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 che il primo set di lavori terminasse prima di iniziare il nuovo set. Ma a causa di nohupciò sembra che vengano eseguiti tutti contemporaneamente.

Ho nohupperché accedo in remoto al mio server e inizio i lavori lì e quindi chiudo la mia bash. C'è una soluzione alternativa?


1
Cerca nel manuale l' waitintegrato.
Satō Katsura,

Risposte:


22

Ti consigliamo di utilizzare il waitcomando per farlo per te. Puoi acquisire tutti gli ID dei processi figlio e attenderli in modo specifico, oppure se sono gli unici processi in background creati dallo script, puoi semplicemente chiamare waitsenza un argomento. Per 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"

6

Alcuni punti:

  • Se il tuo obiettivo nohupè impedire a un'uscita della shell remota di uccidere i tuoi processi di lavoro, dovresti utilizzare nohuplo script stesso, non i singoli processi di lavoro che crea.

  • Come spiegato qui , nohupimpedisce solo ai processi di ricevere SIGHUP e di interagire con il terminale, ma non interrompe la relazione tra la shell e i suoi processi figlio.

  • A causa del punto sopra, con o senza nohup, un semplice waittra i due forloop farà foreseguire il secondo solo dopo che tutti i processi figlio avviati dal primo forsono terminati.

  • Con un semplice wait:

    tutti i processi figlio attualmente attivi sono attesi e lo stato di ritorno è zero.

  • Se devi eseguire il secondo forsolo se non ci sono errori nel primo, dovrai salvare il PID di ciascun lavoratore $!e passarlo a wait:

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }

Potrebbero esserci altri lavori in esecuzione sul server. Quindi vorrei solo aspettare il mio batch .. sono script R, quindi vengono eseguiti sotto Ro cc1plusnel topcomando
masfenix

Inoltre vorrei usare nohup all'interno per eseguire tutti i comandi in "parallelo". fondamentalmente si tratta di simulazioni per un programma scientifico. Voglio eseguire 180 simulazioni in totale, ma in lotti di 60. Il contatore deve anche passare da 1 a 180. Se le eseguo una alla volta, ci vorrà troppo tempo.
Masfenix,

waitfa bashaspettare i lavori in background generati, nient'altro. Potrebbe esserci un po 'di confusione qui: questi forloop, li hai salvati in un file e li hai invocati come uno script (cosa ho ipotizzato, a causa della ##scriptlinea) o li stai digitando a mano nel terminale?
Matei David,

-1

Usa il fgbuilt-in. Attende il completamento dei processi in background.

Prova help fgper i dettagli.


Uno script viene eseguito senza controllo del lavoro.
Kusalananda

-1

Se si inserisce qualcosa come il seguente segmento di codice tra i due forloop, potrebbe essere utile.

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 Rscriptha la possibilità di non essere completata correttamente e di rimanere in giro, il tuo secondo ciclo potrebbe non avere la possibilità di essere eseguito. Il segmento di codice sopra presuppone che tutti i processi con l'identificatore Rscript --vanillavengano completati e scompaiano correttamente. Senza sapere cosa fa la tua applicazione e come funziona, devo fare affidamento su questo presupposto.

MODIFICARE

Alla luce dei commenti, questo si adatterebbe meglio alle tue esigenze. (include il codice originale e la logica di verifica 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

Il nome del processo in topmostra a Rvolte o cc1plus.
masfenix,

In tal caso, dovrai trovare un denominatore comune, visualizzato ps -efnell'elenco. O dopo ogni nohupcomando, registra il PID in una variabile (preferibilmente un array) da echo ${!}e controlla questo gruppo di PID. Quando tutti scompaiono, puoi procedere al secondo forciclo
MelBurslan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.