%20n%C3%A3o%20funciona%20no%20script.png)
Estou tentando fazer um loop até que um processo em segundo plano (iniciado anteriormente no script) seja concluído. Um caso de teste facilmente reproduzível é:
ping -c 10 localhost &>/dev/null &
Na linha de comando, posso fazer um loop while [[ -n $(jobs) ]]
(enquanto $(jobs)
não é nulo).
$ ping -c 10 localhost &>/dev/null &
[1] 19078
$ while [[ -n $(jobs) ]]; do echo -n .; sleep 1; done
.........[1]+ Done ping -c 5 localhost &> /dev/null
No entanto, as mesmas duas linhas em um script continuarão imprimindo .
s até eu acertar Ctrl-C
.
Estranhamente, se eu chamar jobs
dentro do loop, o script termina conforme o esperado.
$ ./background-ping.sh
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Done ping -c 5 localhost &> /dev/null
Estou ciente de que existem outras maneiras de verificar se o trabalho em segundo plano foi concluído (por exemplo, verificação /proc
), mas quero saber por que a verificação jobs
não funciona conforme o esperado.
Responder1
Se entendi seu problema, suas 2 linhas não pararão em um script.
Foi isso que fiz no meu:
ping -c 5 google.com &>/dev/null &
while [[ -n $(jobs -r) ]]; do echo -n "."; sleep 1; done
jobs -r
verifica os processos em execução e a chamada do meu script funciona conforme o esperado, o script para quando o ping é concluído.
EDIT: Acho que em um script o processo pai é conhecido como um processo em execução e é por isso que jobs
continuo pensando que existe um processo em execução. Isso é uma hipótese
Essa é a resposta? (ou talvez eu realmente não entenda o que você quer dizer, meu inglês ruim pode ser o problema...)
Responder2
Sempre que você tiver problemas como esse, você deve sempre tentar imprimir suas variáveis para entender o que está acontecendo. Neste caso, jobs
também retorna trabalhos finalizados. Se você executar isso:
ping -c 5 localhost &>/dev/null &
while [[ -n $(jobs | tee -a temp) ]]; do
echo -n .;
sleep 1;
done
Você verá a seguinte saída em temp
:
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[...]
Então, a saída jobs
aqui nunca está vazia. Mesmo quando o trabalho termina, jobs
ainda retorna a Done
mensagem. É por isso que a solução do Metal3d jobs -r
funcionou.
O que é mais confuso é por que a execução jobs
dentro do loop faz com que ele funcione corretamente. A resposta terá algo a ver com o fato de while [[ -n $(jobs) ]]
ser executado jobs
em um subshell separado, mas não tenho certeza dos detalhes. Eu tenhopostou uma perguntasobre isso na U&L se alguém estiver interessado.
Responder3
Você pode usar wait
o comando que espera que os trabalhos em segundo plano sejam interrompidos
Exemplo:
$ ping -c 10 localhost &>/dev/null &
[29787]
$ wait
[1]+ Done ping -c 10 localhost &>/dev/null
O comando wait é bloqueado e quando ping
terminar, o prompt é liberado e imprime uma mensagem.
Você pode usar is com vários comandos:
$ ping -c 5 localhost &>/dev/null & ping -c 5 facebook.com &>/dev/null &
[1] 29867
[2] 29868
$ wait
[1]- Done ping -c 5 localhost &>/dev/null
[2]+ Done ping -c 5 facebook.com &>/dev/null