Como obter uma lista de todos os processos filhos gerados por um script

9

Contexto:

Os usuários me fornecem seus scripts personalizados para execução. Esses scripts podem ser de qualquer tipo, como scripts para iniciar vários programas GUI, serviços de back-end. Não tenho controle sobre como os scripts são escritos. Esses scripts podem ser do tipo de bloqueio, ou seja, a execução aguarda até que todos os processos filhos (programas executados sequencialmente) saiam

#exaple of blocking script
echo "START"
first_program 
second_program 
echo "DONE"

ou não bloqueador, ou seja, aqueles que bifurcam o processo filho em segundo plano e saem algo como

#example of non-blocking script
echo "START"
first_program &
second_program &
echo "DONE"

O que estou tentando alcançar?

Os scripts fornecidos pelo usuário podem ser de qualquer um dos dois tipos acima ou misturar os dois. Meu trabalho é executar o script e aguardar até que todos os processos iniciados por ele saiam e, em seguida, encerre o nó. Se for do tipo de bloqueio, case é muito simples, ou seja, obtenha o PID do processo de execução do script e aguarde até que o ps -ef | grep -ef PID não tenha mais entradas. Scripts sem bloqueio são os que me dão problemas

Existe uma maneira de obter uma lista de PIDs de todo o processo filho gerado pela execução de um script? Quaisquer sugestões ou sugestões serão muito apreciadas

irraju
fonte
Acho que não é possível após o script pai terminar, a menos que você possa capturar o PID do pai. Se você estiver iniciando os scripts, poderá envolvê-los em algo como o pid$(foo.sh; echo $!)que fornecerá o PID foo.shpara que você possa usá-lo ps --ppid. Isso vai funcionar?
terdon 6/09/13
2
Os scripts precisam ser executados sob o UID do usuário autor? Caso contrário, você pode criar um usuário fictício apenas para esse fim? Você nem precisaria grep, apenas ps –udummy_user. Além disso, observe os grupos de processos.
7113 Scott
Este é mais um tipo de solução alternativa do que uma solução para sua pergunta inicial: Abra uma nova sessão do bash. Você pode listar todos os processos gerados neste shell usando pssem argumentos (deve ser apenas bashe psno início). Inicie seu script lá. Depois de concluído, aguarde até ps | wc -latingir o valor esperado.
Tim

Respostas:

8

Para responder sua pergunta diretamente, o comando

jobs -p

fornece a lista de todos os processos filhos.

Alternativa # 1

Mas no seu caso, pode ser mais fácil usar o comando waitsem nenhum parâmetro:

first_program &
second_program &
wait

Isso aguardará até que TODOS os processos filhos sejam concluídos.

Alternativa # 2

Outra alternativa é usar $!para obter o PID do último programa e talvez se acumular em uma variável, assim:

pids=""
first_program &
pids="$pids $!"
second_program &
pids="$pids $!"

e use wait com isso (caso você deseje apenas esperar por um subconjunto de seus processos filhos):

wait $pids

Alternativa # 3

OU, se você quiser esperar apenas até que QUALQUER processo termine, poderá usar

wait -n $pids

Informações sobre bônus

Se você deseja que um sigterm em seu script bash feche também os processos filhos, será necessário propagar o sinal com algo assim (coloque-o em algum lugar no topo, antes de iniciar qualquer processo):

trap 'kill $(jobs -p)' SIGINT SIGTERM EXIT
Vlad A Ionescu
fonte
1

Obrigado pessoal por suas respostas .. Eu tenho a solução em stackoverflow

Você pode esperar para aguardar a conclusão de todos os processos em segundo plano iniciados pelo userscript. Como a espera funciona apenas em filhos do shell atual, você precisará originar o script deles em vez de executá-lo como um processo separado.

(fonte userscript; aguarde)

A terceirização do script em um subshell explícito deve simular o início de um novo processo de maneira suficientemente próxima. Caso contrário, você também pode colocar em segundo plano o subshell, o que força um novo processo a ser iniciado e aguarde a conclusão.

(fonte userscript; aguarde) e aguarde

Aqui está o link para a resposta original de @chepner: /programming/18663196/how-to-get-list-of-all-child-process-spawned-by-a-script/18663969?noredirect = 1 # 18663969

irraju
fonte
3
Pensei nisso também, mas esta solução falha quando o userscript inicia um subscrito em segundo plano, que inicia outro script em segundo plano. Seu waitcomando aguardará os filhos do script de usuário, mas não os netos.
Tim
@Tim Apenas percebi que :(
irraju 10/09