Minha abordagem seria esta:
-
Executar comando como processo em segundo plano 1
-
Execute o "temporizador de vigia" como processo de segundo plano
-
Configure um manipulador para interceptar um sinal de terminação no shell pai
-
Aguarde a conclusão de ambos os processos. O processo que termina primeiro envia o sinal de terminação para o pai.
-
O manipulador de armaduras do pai mata ambos os processos em segundo plano por meio do controle do job (um deles já foi terminado por definição, mas esse kill será inofensivo no-op porque não estamos usando PIDs, veja abaixo)
Eu tentei contornar a possível condição de disputa endereçada nos comentários usando os IDs de controle de tarefas do shell (que não seriam ambíguos nessa instância do shell) para identificar os processos em segundo plano a serem eliminados, em vez dos PIDs do sistema.
#!/bin/sh
TIMEOUT=$1
COMMAND='sleep 5'
function cleanup {
echo "SIGTERM trap"
kill %1 %2
}
trap cleanup SIGTERM
($COMMAND; echo "Command completed"; kill $$) &
(sleep $TIMEOUT; echo "Timeout expired"; kill $$) &
wait
echo "End of execution"
Resultado para TIMEOUT=10
(o comando termina antes do watchdog):
$ ./timeout.sh 10
Command completed
SIGTERM trap
End of execution
Resultado para TIMEOUT=1
(watchdog termina antes do comando):
$ ./timeout.sh 1
Timeout expired
SIGTERM trap
End of execution
Resultado para TIMEOUT=5
(watchdog e comando terminam "quase" simultaneamente):
./tst.sh 5
Timeout expired
Command completed
SIGTERM trap
End of execution