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.