Um ERR trap não será acionado se um código de erro for imediatamente "capturado", o que significa que você pode usar as declarações if e outros sem ter que ativar a detecção de erros fora o tempo todo. No entanto, você não pode usar a verificação de $? para o controle de fluxo, porque conforme o tempo que você chega a essa verificação, você já (pode) ter o erro não detectado.
Se você tiver um comando que espera falhar - e você não deseja que as falhas disparem o trap , você simplesmente terá que detectar a falha. Envolvê-los em uma instrução if é desajeitado e detalhado, mas essa abreviação funciona bem:
/bin/false || : # will not trigger an ERR trap
No entanto, se você quiser fazer alguma coisa quando um comando falhar, if ficará bem aqui:
if ! /bin/false; then
echo "this was not caught by the trap!"
fi
Ou, como alternativa, else também detectará o estado do erro:
if /bin/false; then
: # dead code
else
echo "this was not caught by the trap!"
fi
Em suma, set -e e trap "command" ERR só são desarmados se houver uma condição de erro que não é imediatamente considerada intrinsecamente.