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

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

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

Eu tenho nohup porque eu loguei remotamente em meu servidor e iniciei os trabalhos lá e então fechei meu bash. Existe uma solução alternativa?

Comentários

  • Pesquise no manual pelo wait integrado.

Resposta

Você vai querer usar o comando wait para faça isso por você. Você pode capturar todos os IDs de processos filhos e esperar por eles especificamente ou, se eles forem os únicos processos em segundo plano que seu script está criando, basta 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" 

Resposta

Alguns pontos:

  • Se seu objetivo com nohup é evitar 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 que ele cria.

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

  • Por causa do ponto acima, com ou sem nohup, um simples wait entre os dois for loops causará o segundo for para ser executado somente depois que todos os processos filho iniciados pelo primeiro for tenham saído.

  • Com um wait:

    todos os processos filho ativos atualmente são aguardados e o status de retorno é zero.

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

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

Comentários

  • Pode haver Seriam outros trabalhos em execução no servidor. Então, eu ' d quero apenas aguardar meu lote .. eles são scripts R, portanto, são executados em R ou cc1plus no top comando
  • Também eu ' d gostaria de usar nohup dentro para executar todos os comandos em " paralelo ". basicamente, 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, vai demorar muito.
  • wait faz com que bash espere pelos trabalhos de segundo plano que ele mesmo gerou, nada mais. Pode haver alguma confusão aqui- estes for loops, você os salvou em um arquivo e os chamou como um script (o que presumi, por causa do ##script linha), ou você está digitando-os manualmente no terminal?
  • Eu estava fazendo cat file.txt | while e o pids não foi definido fora do loop portanto, o comando de espera viu uma string $pids vazia. por que isso acontece é discutido em serverfault.com/q/259339 . facilmente corrigido como while ... < files.txt conforme respondido em serverfault.com/a/259346
  • Apenas curioso qual é a finalidade do sinal + com a variável pids?

Resposta

Use o fg integrado. Ele aguarda até que os processos em segundo plano terminem.

Tente help fg para obter detalhes.

Comentários

  • Um script é executado sem controle de trabalho.

Resposta

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

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

Claro, se seu aplicativo Rscript tem uma chance de não completar com sucesso e demorar, seu segundo loop for pode não ter a chance de rodar. O segmento de código acima pressupõe que 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 funciona, tenho que confiar nessa suposição.

EDITAR

À luz dos comentários, isso seria melhor suas necessidades. (inclui 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 

Comentários

  • O processo nome em top mostra R às vezes ou cc1plus.
  • Nesse caso, você precisará encontrar um denominador comum, aparecendo na lista ps -ef. Ou depois de cada comando nohup, registre o PID em uma variável (de preferência uma matriz) por echo ${!} e verifique este grupo de PIDs. Quando todos eles desaparecerem, você pode prosseguir para o segundo for loop

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *