OBJETIVO DO SCRIPT: o script é invocado como ./script.sh cmd1 cmd2 ... cmdn
. Deve executar em segundo plano todos os comandos passados como argumentos da linha de comando e verificar quando todos terminaram sua execução. Além disso, se o sinal SIGTERM for enviado para o script, ele deve matar todos os processos mencionados ( cmd1 ... cmdn
) e depois se matar.
PROBLEMA: Tudo parece funcionar, exceto o autotermination e não consigo descobrir o porquê. Eu tentei usar kill $$
, mas em tempo de execução eu recebo segmentation fault
. Eu estava pensando que o problema estava relacionado ao fato de o kill
comando estar dentro de uma função, mas por outro lado, se eu comentar kill $$
e deixar kill ${PIDAR[*]}
o comando, o último funciona. Alguém poderia me explicar o que estou perdendo?
#!/bin/bash
# signal handler
killemall () {
echo $$
kill ${PIDAR[*]}
kill $$ # implicated line
}
PIDAR=() # pid array
STAR=() # process state array
# execute processes in bg and save their pid
for i in "$@" ; do
$i &
PIDAR+=($!)
done
trap 'killemall' SIGTERM
terminated=1 # flag to indicate when all processes are terminated
while sleep 1 && [ $terminated -eq 1 ]; do
for (( i=0; i<${#PIDAR[*]}; i++ )); do
STAR[$i]=$(ps hp ${PIDAR[$i]} | awk '{ print $3 }')
if [ -z ${STAR[$i]} ]; then
terminated=0
else terminated=1
fi
echo "Process state ${PIDAR[$i]}:${STAR[$i]}" | tee -a logg
done
done
echo "All processes are terminated"
Obrigado
SOLUÇÃO: como o usuário18197 apontou, o problema está chamando kill $$
. De fato, como a kill
página de manual relata:
O sinal padrão para kill é TERM
Então, a cada kill $$
chamada, o script chamava o manipulador killemall
que, por sua vez, chamava novamente kill $$
e assim por diante recursivamente. Para evitar esse comportamento, podemos liberar SIGTERM
o sinal. Como help trap
relatórios:
Se ARG estiver ausente (e um único SIGNAL_SPEC for fornecido) ou `-', cada sinal especificado é redefinido para seu valor original.
Assim, o novo corpo da função é:
killemall () {
echo $$
trap - SIGTERM
kill ${PIDAR[@]}
kill $$
}
Não consegui reproduzir a falha de seg, mas estou supondo que enviar SIGTERM para você mesmo irá invocar novamente a função killemall, que irá enviar SIGTERM, que irá invocar o killemall...
Na verdade, você não precisa fazer nada para encerrar seu script. A função
killemall
é chamada e, quando terminar, o script será encerrado. Você pode adicionar umexit 0
no final da função para torná-la mais clara, se desejar.