Primeiro de tudo, caso não seja óbvio, o script na pergunta falha
porque heartbeat
é executado em um processo filho
e, portanto, não pode alterar as variáveis do shell na memória do shell pai.
Aqui está uma abordagem mais próxima do espírito da tentativa do OP:
#!/bin/bash
trap 'do_different=true' USR1
heartbeat() {
while sleep 5
do # If the parent process has gone away, the child should terminate.
kill -USR1 "$$" || exit
done
}
heartbeat &
heartbeat_pid=$!
trap 'kill "$heartbeat_pid"' 0
do_different=true
while true
do
if "$do_different"
then
echo 'Something different'
do_different=false
i=0
else
# process of random duration; not important
r=$(( 1 + RANDOM % 3 ))
sleep "$r"
i=$((i + r))
echo "$i"
fi
done
O heartbeat
modificado envia sinais SIGUSR1
para o processo de shell principal (pai).
Isso e SIGUSR2 são reservados para uso do usuário / aplicativo
(e nunca deve ser gerado pelo sistema).
O comando trap
permite que um script de shell capture sinais.
O comando trap 'do_different=true' USR1
informa ao shell
para capturar o sinal SIGUSR1 (que chega a cada cinco segundos)
e defina o sinalizador do_different
quando ocorrer.
heartbeat_pid
, obviamente, é o ID do processo (PID)
do processo filho heartbeat
.
O comando trap 'kill "$heartbeat_pid"' 0
define uma ação para ocorrer
mediante "recibo" do pseudo-sinal 0, que se refere à saída do script.
Pense nisso como a casca colocando uma nota na porta
dizendo "Depois de sair, lembre-se de comprar mantimentos a caminho de casa".
Esta ação será invocada
se o script chegar ao final ou executar uma declaração exit
(nenhum dos quais pode acontecer com este script, já que é um loop infinito),
ou se é terminado por um sinal de interrupção
(SIGINT, que é gerado por Ctrl + C ).
Esta é uma rede de segurança;
o processo heartbeat
já está escrito para terminar
quando o processo pai desaparece.