Estou interceptando INT e ERR com o seguinte código
set -ex -o pipefail
dest=$(mktemp -d)
cd "$dest"
trap "echo; echo Clean up; rm -rf $dest" INT ERR
sleep 9999
Quando pressiono ^C
o retorno de chamada de limpeza é executado várias vezes
++ echo Clean up
Clean up
++ rm -rf /tmp/tmp.KYXL110516
++ echo
++ echo Clean up
Clean up
++ rm -rf /tmp/tmp.KYXL110516
Esse é o comportamento esperado? É possível executá-lo apenas uma vez?
Você está recebendo os sinais INT e ERR; SIGINT é entregue a
sleep
, que sai com um código de retorno diferente de zero. O código de retorno diferente de zero aciona a armadilha para SIGERR.Um exemplo, para ver as armadilhas separadas:
Executando, depois Control-C:
Quanto a chamar a armadilha apenas uma vez, uma opção seria redefinir a
ERR
armadilha enquanto estiver dentro daINT
armadilha:... o que resulta em:
Em
bash
, você pode simplesmente substituir isso portrap "my-cleanup-command" EXIT
. Essa armadilha será executada quando o script sair, inclusive se for enviado SIGINT. Na minha opinião, esta é geralmente a abordagem mais elegante...Exceto pelo fato de ser específico do bash. Os traps EXIT são mencionados no POSIX, mas o comportamento não é especificado. Em muitos outros shells, o trap EXIT não é executado se o shell sair devido a um sinal.
https://unix.stackexchange.com/a/57960/29483
Às vezes eu realmente odeio scripts de shell :).
Olhando para a resposta vinculada, acho que uma maneira menos específica do bash de garantir que nenhum código seja executado após a primeira armadilha seria sair imediatamente. Parece que há diferentes maneiras de fazer isso, mas aqui está a mais simples que eu tentaria.