pausando um script bash até que os comandos anteriores sejam concluídos

20

Eu tenho um script bash que se parece 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

Gostaria de criar outro loop for após o primeiro para continuar por mais 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

Gostaria que o primeiro conjunto de tarefas terminasse antes de iniciar o novo conjunto. Mas por causa nohupdisso, parece que todos eles são executados simultaneamente.

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

masfenix
fonte
11
Procure o manual para o waitembutido.
Satō Katsura

Respostas:

22

Você deseja usar o waitcomando para fazer isso por você. Você pode capturar todos os IDs de processo filhos e esperar por eles especificamente, ou se eles são os únicos processos em segundo plano que seu script está criando, basta ligar waitsem 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"
ParanoidGeek
fonte
6

Alguns pontos:

  • Se seu objetivo nohupé impedir que uma saída remota do shell mate seus processos de trabalho, você deve usar nohupno próprio script, não nos processos de trabalho individuais que ele cria.

  • Conforme explicado aqui , nohupapenas impede que os processos recebam o SIGHUP e interajam com o terminal, mas não interrompe o relacionamento entre o shell e seus processos filhos.

  • Por causa do ponto acima, com ou sem nohup, um simples waitentre os dois forloops fará com que o segundo forseja executado somente após a saída de todos os processos filhos iniciados pelo primeiro for.

  • Com um simples wait:

    todos os processos filhos ativos no momento são aguardados e o status de retorno é zero.

  • Se você precisar executar o segundo forapenas se não houver erros no primeiro, precisará salvar cada PID de trabalhador $!e passar todos eles para wait:

    pids=
    for ...
        worker ... &
        pids+=" $!"
    done
    wait $pids || { echo "there were errors" >&2; exit 1; }
Matei David
fonte
Pode haver outros trabalhos em execução no servidor. Então, eu só quero esperar para o meu lote .. eles são scripts R assim que são executados sob Rou cc1plusno topcomando
masfenix
Também gostaria de usar nohup dentro para executar todos os comandos em "paralelo". Basicamente, essas são simulações para um programa científico. Quero executar 180 simulações no total, mas em lotes de 60. O contador também precisa ir de 1 a 180. Se eu fizer uma de cada vez, levará muito tempo.
masfenix
waitfaz bashesperar pelos trabalhos em segundo plano que gerou a si próprio, nada mais. Pode haver alguma confusão aqui - esses forloops, você os salvou em um arquivo e os invocou como um script (o que eu assumi, por causa da ##scriptlinha), ou você os está digitando manualmente no terminal?
Matei David
-1

Use o fgbuiltin. Aguarda até que os processos em segundo plano sejam concluídos.

Tente help fgpara detalhes.

Luchostein
fonte
Um script é executado sem controle de trabalho.
Kusalananda
-1

Se você inserir algo como o seguinte segmento de código entre seus dois forloops, isso poderá ajudar.

flag=0

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

Obviamente, se o seu aplicativo Rscripttiver uma chance de não ser concluído com êxito e permanecer por aí, o segundo loop for poderá não ter a chance de ser executado. O segmento de código acima pressupõe que todos os processos com o identificadorRscript --vanilla serão concluídos e desaparecerão corretamente. Sem saber o que seu aplicativo faz e como ele é executado, tenho que confiar nessa suposição.

EDITAR

À luz dos comentários, isso melhor atenderia às suas necessidades. (inclui o código original e 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
MelBurslan
fonte
O nome do processo em topmostra Ràs vezes ou cc1plus.
masfenix
Nesse caso, você precisará encontrar um denominador comum, aparecendo na ps -eflista. Ou após cada nohupcomando, registre o PID em uma variável (de preferência uma matriz) echo ${!}e verifique esse grupo de PIDs. Quando todos eles desaparecem, você pode avançar para o segundo forciclo
MelBurslan