Basta alterar o início do seu trap
para verificar o código de retorno
do último comando (que será o da saída, ou o comando em
o fim do script) para zero. Ou seja
trap '[ $? = 0 ] && exit;'"..."
onde "..."
é sua string atual, que deve ser seguida sem espaços intermediários. Uma saída dentro da armadilha não será capturada novamente.
Se a sua armadilha também estiver lidando com sinais, por exemplo, SIGINT (controle-C), então
a armadilha é chamada uma vez para o SIGINT, então mais uma vez para a saída.
Provavelmente, você pode verificar se o trap está sendo chamado de SIGINT, pois o $?
será 128 + n, onde n é o sinal, portanto, 130 para SIGINT. Lembre-se que $?
será alterado assim que você der outro comando, então talvez comece com rc=$?;
e use $rc
em seus testes.