Fazer loop até que o processo em segundo plano seja concluído (com 'jobs') não funciona no script

1

Estou tentando fazer um loop até que um processo em segundo plano (iniciado anteriormente no script) esteja completo. Um caso de teste facilmente reproduzível é:

ping -c 10 localhost &>/dev/null &

Na linha de comando, posso fazer um loop em 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é que eu atinja Ctrl-C .

Estranhamente, se eu chamar jobs dentro do loop, o script termina como 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 há outras maneiras de verificar se o trabalho em segundo plano está completo (por exemplo, verificando /proc ), mas quero saber por que a verificação de jobs não funciona como esperado.

    
por stephenwade 24.03.2015 / 01:40

3 respostas

2

Se eu entendi seu problema, suas duas linhas não param em um script.

Isso é o que eu fiz no meu:

ping -c 5 google.com &>/dev/null &
while [[ -n $(jobs -r) ]]; do echo -n "."; sleep 1; done

jobs -r verifica processos em execução e, ao chamar meu script, o esperado, o script pára quando o ping é concluído.

EDIT: Eu acho que em um script o processo pai é conhecido como um processo em execução e é por isso que jobs continuam a pensar que há um processo em execução. Essa é uma hipótese

Essa é a resposta? (ou talvez eu realmente não entenda o que você quer dizer, meu pobre inglês pode ser o problema ...)

    
por 24.03.2015 / 02:10
1

Sempre que você tiver problemas como esse, sempre tente imprimir suas variáveis para entender o que está acontecendo. Nesse caso, jobs também retorna trabalhos concluídos. Se você executar isto:

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
[...]

Portanto, a saída de jobs aqui nunca está vazia. Mesmo quando o trabalho for concluído, jobs ainda retornará a mensagem Done . É por isso que a solução da Metal3d usando jobs -r funcionou.

O que é mais confuso é porque executar jobs dentro do loop faz com que ele funcione corretamente. A resposta será algo a ver com o fato de que while [[ -n $(jobs) ]] executa jobs em um subshell separado, mas não tenho certeza sobre os detalhes. Eu tenho postado uma pergunta sobre isso em U & L, se alguém estiver interessado.

    
por 24.03.2015 / 11:33
0

Você pode usar o comando wait que aguarda que as tarefas em segundo plano sejam interrompidas

Exemplo:

$ ping -c 10 localhost &>/dev/null &
[29787]
$ wait
[1]+  Done ping -c 10 localhost &>/dev/null

O comando de espera bloqueia e quando ping terminou, o prompt é liberado e, em seguida, imprime uma mensagem.

Você pode usar 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
    
por 24.03.2015 / 01:50