Existe algum recurso interno no Bash para aguardar a conclusão de um processo?
O wait
comando permite apenas aguardar a conclusão dos processos filhos. Gostaria de saber se há alguma maneira de aguardar a conclusão de qualquer processo antes de prosseguir em qualquer script.
Uma maneira mecânica de fazer isso é a seguinte, mas eu gostaria de saber se existe algum recurso interno no Bash.
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
Respostas:
Para aguardar a conclusão de qualquer processo
Linux:
Darwin (requer que
$pid
tenha arquivos abertos):Com tempo limite (segundos)
Linux:
Darwin (requer que
$pid
tenha arquivos abertos):fonte
tail
faria isso.tail
trabalha sob o capô pesquisandokill(pid, SIG_0)
um processo (descoberto usandostrace
).+r 1
seja, o tempo limite, estou procurando pessoalmente uma solução para o MacOS que não use sondagem.tail
tem a linhakill (pid, 0) != 0 && errno != EPERM
.caffeinate -w $pid
fará o truque.Não há embutido. Use
kill -0
em loop para uma solução viável:Ou como um oneliner mais simples para facilitar o uso único:
Conforme observado por vários comentaristas, se você deseja aguardar processos para os quais não tem o privilégio de enviar sinais, há outra maneira de detectar se o processo está sendo executado para substituir a
kill -0 $pid
chamada. No Linux,test -d "/proc/$pid"
funciona, em outros sistemas que você pode precisar usarpgrep
(se disponível) ou algo parecidops | grep "^$pid "
.fonte
sleep 0.5
, o processo com$pid
pode morrer e outro processo pode ser criado com o mesmo$pid
. E vamos acabar esperando por 2 processos diferentes (ou até mais) com o mesmo$pid
.Eu descobri que "kill -0" não funciona se o processo é de propriedade do root (ou outro), então usei o pgrep e criei:
Isso teria a desvantagem de provavelmente corresponder aos processos zumbis.
fonte
kill(pid, sig=0)
falha se o processo do responsável pela chamada não tiver um privilégio de matar. Assim, / bin / kill -0 e "kill -0" (bash embutido) também falham na mesma condição.Esse loop do script bash termina se o processo não existir ou se for um zumbi.
EDIT : O script acima foi dado abaixo pela Rockallite . Obrigado!
Minha resposta original abaixo funciona para Linux, contando com
procfs
ie/proc/
. Não conheço sua portabilidade:Não se limita ao shell, mas os SOs não têm chamadas de sistema para assistir ao encerramento de processos não-filhos.
fonte
grep /proc/$PID/status
com aspas (bash: test: argument expected
)while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do sleep 1; done
ps
, nem-p
ous=
são suportadosO FreeBSD e o Solaris possuem esse
pwait(1)
utilitário útil , que faz exatamente o que você deseja.Acredito que outros sistemas operacionais modernos também tenham as chamadas de sistema necessárias (o MacOS, por exemplo, implementa o BSD
kqueue
), mas nem todos o disponibilizam na linha de comando.fonte
> BSD and Solaris
: Inspecionando os três grandes BSDs que vêm à mente; nem o OpenBSD nem o NetBSD têm essa função (em suas páginas de manual), apenas o FreeBSD possui, como você pode verificar facilmente em man.openbsd.org .kqueue
, então compilar o FreeBSDpwait(1)
seria trivial, no entanto. Por que os outros do BSD não iria importar o recurso me escapa ...plink me@oracle box -pw redacted "pwait 6998";email -b -s "It's done" etc
apenas me permitiu ir para casa agora, em vez de horas a partir de agora.Na página de manual do bash
fonte
wait
Sem args, o processo será bloqueado até que os processos filhos sejam concluídos. Honestamente, não vejo motivo para esperar por nenhum processo, pois sempre há processos do sistema em andamento.sleep 1000
ctrl-z
wait [sleep pid]
retorna imediatamenteTodas essas soluções são testadas no Ubuntu 14.04:
Solução 1 (usando o comando ps): Apenas para adicionar a resposta de Pierz, sugiro:
Nesse caso,
grep -vw grep
garante que o grep corresponda apenas ao process_name e não ao próprio grep. Tem a vantagem de suportar os casos em que o process_name não está no final de uma linha emps axg
.Solução 2 (usando o comando top e o nome do processo):
Substitua
process_name
pelo nome do processo que aparece emtop -n 1 -b
. Por favor, mantenha as aspas.Para ver a lista de processos que você espera que sejam concluídos, você pode executar:
Solução 3 (usando o comando superior e o ID do processo):
Substitua
process_id
pelo ID do processo do seu programa.fonte
grep -v grep
pipeline é um antipadrão massivo, e isso pressupõe que você não tenha processos não relacionados com o mesmo nome. Se você conhece os PIDs, isso pode ser adaptado a uma solução que funcione corretamente.-w
para evitar o problema degrep -v grep
alguma extensão . Também adicionei mais duas soluções com base no seu comentário.Ok, parece que a resposta é - não, não existe uma ferramenta integrada.
Depois de definir
/proc/sys/kernel/yama/ptrace_scope
para0
, é possível usar ostrace
programa. Outros comutadores podem ser usados para silenciá-lo, para que ele realmente espere passivamente:fonte
Operation not permitted
a segunda instância de strace); você pode confirmar isso?(...)"tracee" always means "(one) thread"
(e confirmo o erro que você mencionou). Para permitir que mais processos esperem dessa maneira, você teria que fazer uma cadeia.Solução de bloqueio
Use o
wait
em um loop, para aguardar o término de todos os processos:Esta função sai imediatamente, quando todos os processos foram finalizados. Esta é a solução mais eficiente.
Solução sem bloqueio
Use o
kill -0
loop, para aguardar o término de todos os processos + faça qualquer coisa entre as verificações:O tempo de reação diminuiu para o
sleep
tempo, porque é necessário impedir o alto uso da CPU.Um uso realista:
Aguardando o término de todos os processos + informe o usuário sobre todos os PIDs em execução.
Notas
Essas funções obtêm PIDs por meio de argumentos
$@
como array BASH.fonte
Teve o mesmo problema, resolvi o problema encerrando o processo e aguardando a conclusão de cada processo usando o sistema de arquivos PROC:
fonte
Não há recurso interno para aguardar a conclusão de qualquer processo.
Você pode enviar
kill -0
para qualquer PID encontrado, para não ficar intrigado com zumbis e outras coisas que ainda estarão visíveisps
(enquanto ainda recupera a lista de PIDsps
).fonte
Use inotifywait para monitorar algum arquivo que é fechado quando o processo terminar. Exemplo (no Linux):
-e especifica o evento a aguardar, -q significa saída mínima apenas na finalização. Nesse caso, será:
Um único comando de espera pode ser usado para aguardar vários processos:
A sequência de saída do inotifywait informará qual processo foi finalizado. Isso funciona apenas com arquivos 'reais', não com algo em / proc /
fonte
Em um sistema como o OSX, você pode não ter o pgrep para tentar esta abordagem ao procurar processos pelo nome:
O
$
símbolo no final do nome do processo garante que o grep corresponda apenas ao process_name ao final da linha na saída ps e não a si próprio.fonte
/dev/null
,-q
deve ser usado comgrep
. Outra instância do processo pode ter começado enquanto o seu ciclo estava dormindo e você nunca saberá ...-q
sugestão seja válida, como mencionei na minha resposta, especificamente a terminação$
significa que o grep não corresponderá ao nome "em algum lugar na linha de comando" nem corresponderá a si próprio. Você realmente tentou no OSX?A solução de Rauno Palosaari para
Timeout in Seconds
Darwin
, é uma excelente solução alternativa para um sistema operacional semelhante ao UNIX que não possui GNUtail
(não é específico aDarwin
). Mas, dependendo da idade do sistema operacional do tipo UNIX, a linha de comando oferecida é mais complexa do que o necessário e pode falhar:Em pelo menos um UNIX antigo, o
lsof
argumento+r 1m%s
falha (mesmo para um superusuário):O
m%s
é uma especificação de formato de saída. Um pós-processador mais simples não exige isso. Por exemplo, o seguinte comando aguarda no PID 5959 por até cinco segundos:Neste exemplo, se o PID 5959 sair por conta própria antes dos cinco segundos decorridos,
${?}
será0
. Se não${?}
retornar1
após cinco segundos.Pode-se notar expressamente que em
+r 1
, o1
é o intervalo da pesquisa (em segundos), portanto, ele pode ser alterado para se adequar à situação.fonte