set -e
não é acionado em comandos com falha que são usados como condições na seção de condição das construções if
/ while
/ until
ou à esquerda de ||
, &&
ou em funções, subshells, arquivos originados, eval
ed que são invocados nessas condições.
Se sim, então:
if [ ! -f /custom.log ]; then
Sairá do script se /custom.log
fosse um arquivo regular, pois [
também sairia com um status de saída diferente de zero.
O comando [
builtin do shell bash
(e a maioria das outras implementações) sai com 1
status se a condição testada não for atendida e 2
se houver um erro de sintaxe (nem todos os erros de sintaxe embora, por exemplo, não em [ -v 'a[+]' ]
). POSIX requer que o status de saída seja maior que 1 em caso de erro .
Você pode escolher sair do script se um comando sair com um código maior que 1, independentemente de ser usado em uma condição ou não com algo como:
shopt -s extdebug # make sure the DEBUG trap propagates to subshells
trap '(($?>1 && (ret=$?))) && exit "$ret"' DEBUG
[ -f / ] || echo / not a regular file # OK
[ -f /] || echo was a syntax error # causes an exit, not output
echo not reached
Observe que você não pode usar o ERR
trap para isso, pois o ERR
trap só é executado na mesma condição daqueles que acionam a saída por set -e
.
Agora, cuidado com as implicações. Por exemplo, isso causaria um:
if grep -qs pattern /file; then
echo pattern was found in /file
fi
para sair se /file
não existir ou não for legível, pois grep
retorna com um status 2 nesse caso, mesmo com -s
, a intenção era claramente ignorar esses casos.
Então, você precisa tomar cuidado com as condições em que os comandos usados nas suas condições podem sair com um status maior que 1. Para contornar esses problemas, você precisa de algo como:
if sh -c 'grep -sq pattern / file || exit 1'; then...
Você pode restringir a saída após o status de saída maior que 1 ao comando [
ou test
com algo como:
unset -v previous_BASH_COMMAND
trap '
case $previous_BASH_COMMAND in
("[ "* | "test "*) (($?>1 && (ret=$?))) && exit "$ret"
esac
previous_BASH_COMMAND=$BASH_COMMAND' DEBUG
Isso tem algumas limitações. Em
echo x
([ -f/]; echo y)
Isso faria com que o subshell fosse embora, mas não o pai, já que o $previous_BASH_COMMAND
não foi definido lá. E em:
[ -f / ] && echo a regular file
(grep -qs foo /file && echo foo in /file)
echo here
O shell sairia ao executar echo here
, porque $?
seria 2 e $previous_BASH_COMMAND
seria [ -f / ]
.
Em qualquer caso, coisas como
[ -f /] | cat
export var="$([ -f /])"
não pôde ser detectado, pois o status de saída não é propagado para o processo de shell pai (exceto com a opção pipefail
no primeiro caso).
Agora, não tenho certeza se vale a pena adicionar esse tipo de detecção (frágil) em tempo de execução, quando o erro é facilmente detectável no momento do desenvolvimento (quando você escreve e testa seu script).