pausando um script bash até que os comandos anteriores tenham terminado

9

Eu tenho um script bash parecido com o seguinte:

##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

Eu gostaria de criar outro loop for após o primeiro para continuar por 30. Por exemplo

##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

Eu gostaria que o primeiro conjunto de trabalhos terminasse antes de iniciar o novo conjunto. Mas por causa do nohup parece que todos eles são executados simultaneamente.

Eu tenho nohup porque eu faço login remotamente no meu servidor e inicio os trabalhos lá e depois fecho meu bash. Existe uma solução alternativa?

    
por masfenix 22.08.2016 / 16:59

4 respostas

13

Você vai querer usar o comando wait para fazer isso por você. Você pode capturar todos os IDs de processo filhos e esperá-los especificamente, ou se eles são os únicos processos em segundo plano que seu script está criando, você pode apenas chamar wait sem um argumento. Por exemplo:

#!/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"
    
por 22.08.2016 / 17:17
3

Alguns pontos:

  • Se sua meta com nohup for impedir que uma saída de shell remota mate seus processos de trabalho, você deve usar nohup no próprio script, não nos processos de trabalho individuais criados.

  • Conforme explicado aqui , nohup apenas impede processos de receber SIGHUP e de interagir com o terminal, mas não quebra a relação entre o shell e seus processos filhos.

  • Devido ao ponto acima, com ou sem nohup , um simples wait entre os dois for loops fará com que o segundo for seja executado somente depois que todos os processos filho iniciados pelo primeiro for foram encerrados.

  • Com um simples wait :

    all currently active child processes are waited for, and the return status is zero.

  • Se você precisar executar o segundo for apenas se não houver erros no primeiro, precisará salvar cada PID de trabalho com $! e passá-los todos para wait :

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }
    
por 22.08.2016 / 19:26
-1

Use o fg incorporado. Aguarda até que os processos em segundo plano terminem.

Experimente help fg para mais detalhes.

    
por 22.08.2016 / 17:09
-1

Se você inserir algo como o seguinte segmento de código entre seus dois for loops, isso pode ajudar.

flag=0

while [ flag -eq 0 ]
do
  ps -ef | grep "Rscript --vanilla" | grep -v grep > /dev/null
  flag=${?}
  sleep 10
done

É claro que, se o seu aplicativo Rscript tiver uma chance de não ser concluído com sucesso e persistente, seu segundo loop for pode não ter a chance de ser executado. Segmento de código acima, todos os processos com o identificador Rscript --vanilla serão concluídos e desaparecerão corretamente. Sem saber o que seu aplicativo faz e como ele é executado, preciso confiar nessa suposição.

EDITAR

À luz dos comentários, isso atenderia melhor às suas necessidades. (inclui o seu código original, bem como a lógica de verificação de conclusão)

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
    
por 22.08.2016 / 17:07

Tags