set -e
finaliza o script se um código de saída diferente de zero for encontrado, exceto sob certas condições. Para resumir os perigos de seu uso em poucas palavras: não se comporta como as pessoas pensam.
Na minha opinião, deve ser considerado um hack perigoso que continua a existir apenas para fins de compatibilidade. A set -e
instrução não transforma o shell de uma linguagem que usa códigos de erro em uma linguagem que usa o fluxo de controle do tipo exceção, apenas tenta emular mal esse comportamento.
Greg Wooledge tem muito a dizer sobre os perigos de set -e
:
No segundo link, existem vários exemplos do comportamento não intuitivo e imprevisível de set -e
.
Alguns exemplos do comportamento não intuitivo de set -e
(alguns extraídos do link wiki acima):
set -e
x = 0
deixe x ++
eco "x é $ x"
O exemplo acima fará com que o script shell saia prematuramente, porque let x++
retorna 0, que é tratado pela let
palavra - chave como um valor falso e transformado em um código de saída diferente de zero. set -e
nota isso e termina silenciosamente o script.
set -e
[-d / opt / foo] && echo "Aviso: o foo já está instalado. Será substituído." > & 2
eco "Instalando foo ..."
O procedimento acima funciona como esperado, imprimindo um aviso, se /opt/foo
já existir.
set -e
check_previous_install () {
[-d / opt / foo] && echo "Aviso: o foo já está instalado. Será substituído." > & 2
}
check_previous_install
eco "Instalando foo ..."
O que foi dito acima, apesar da única diferença de que uma única linha foi refatorada em uma função, terminará se /opt/foo
não existir. Isso ocorre porque o fato de ter funcionado originalmente é uma exceção especial ao set -e
comportamento de. Quando a && b
retorna diferente de zero, é ignorado por set -e
. No entanto, agora que é uma função, o código de saída da função é igual ao código de saída desse comando e a função que retorna diferente de zero encerra silenciosamente o script.
set -e
IFS = $ '\ n' lê-d '' -r -a config_vars <config
O acima irá ler a matriz config_vars
do arquivo config
. Como o autor pretende, ele termina com um erro se config
estiver faltando. Como o autor pode não pretender, ele termina silenciosamente se config
não terminar em uma nova linha. Se set -e
não fosse usado aqui, config_vars
conteria todas as linhas do arquivo, terminando ou não em uma nova linha.
Usuários de texto sublime (e outros editores de texto que lidam com novas linhas incorretamente), tenha cuidado.
set -e
should_audit_user () {
grupos de grupos locais = "$ (groups" $ 1 ")"
para grupo em $ groups; Faz
if ["$ group" = auditoria]; então retorne 0; fi
feito
retorno 1
}
if should_audit_user "$ user"; então
madeireiro 'Blah'
fi
O autor aqui pode esperar razoavelmente que, se por algum motivo o usuário $user
não existir, o groups
comando falhará e o script será encerrado em vez de permitir que o usuário execute alguma tarefa não auditada. No entanto, nesse caso, a set -e
rescisão nunca entra em vigor. Se $user
não puder ser encontrado por algum motivo, em vez de encerrar o script, a should_audit_user
função retornará dados incorretos como se set -e
não estivessem em vigor.
Isso se aplica a qualquer função chamada da parte da condição de uma if
instrução, não importa quão profundamente aninhada, não importa onde seja definida, não importa mesmo se você executar set -e
dentro dela novamente. O uso if
a qualquer momento desativa completamente o efeito de set -e
até que o bloco de condições seja totalmente executado. Se o autor não está ciente dessa armadilha ou não conhece toda a pilha de chamadas em todas as situações possíveis em que uma função pode ser chamada, ele escreverá um código de buggy e a falsa sensação de segurança fornecida por set -e
será pelo menos parcialmente culpa.
Mesmo que o autor esteja totalmente ciente dessa armadilha, a solução alternativa é escrever o código da mesma maneira que se escreveria sem set -e
, tornando efetivamente essa troca menos que inútil; não apenas o autor precisa escrever o código de tratamento manual de erros como se set -e
não estivesse em vigor, mas a presença de set -e
pode ter enganado-os a pensar que não precisam.
Algumas desvantagens adicionais de set -e
:
- Ele incentiva código desleixado. Os manipuladores de erros são completamente esquecidos, na esperança de que tudo que falhou reportará o erro de alguma maneira sensata. No entanto, com exemplos como
let x++
acima, este não é o caso. Se o script morre inesperadamente, geralmente é silencioso, o que dificulta a depuração. Se o script não morrer e você esperava (veja o ponto anterior), você tem um bug mais sutil e insidioso em suas mãos.
- Isso leva as pessoas a uma falsa sensação de segurança. Veja novamente o
if
marcador de condição.
- Os locais onde o shell termina não são consistentes entre os shells ou as versões do shell. É possível escrever acidentalmente um script que se comporte de maneira diferente em uma versão mais antiga do bash devido ao comportamento de
set -e
ter sido ajustado entre essas versões.
set -e
é uma questão controversa, e algumas pessoas cientes dos problemas que a cercam recomendam, enquanto outras recomendam tomar cuidado enquanto estiver ativo para conhecer as armadilhas. Existem muitos iniciantes em scripts de shell que recomendam set -e
em todos os scripts um exemplo geral para condições de erro, mas na vida real isso não funciona dessa maneira.
set -e
não substitui a educação.