Considere os comandos
eval false || echo ok
echo also ok
Normalmente, esperamos que isso execute o false
utilitário e, como o status de saída é diferente de zero, execute echo ok
e echo also ok
.
Em todos os shells do tipo POSIX que eu uso ( ksh93
, zsh
, bash
, dash
, OpenBSD ksh
e yash
), é isso que acontece, mas as coisas ficam interessantes se habilitarmos o set -e
.
Se set -e
estiver em vigor, o OpenBSD sh
e os ksh
shells (ambos derivados de pdksh
) encerrarão o script ao executar o eval
. Nenhum outro shell faz isso.
O POSIX diz que um erro em um utilitário interno especial (como eval
) deve fazer com que o shell não interativo seja encerrado. Não tenho certeza se a execução false
constitui "um erro" (se fosse, seria independente de set -e
estar ativo).
A maneira de contornar isso parece ser colocar o eval
em um sub shell,
( eval false ) || echo ok
echo also ok
A questão é se eu devo ter que fazer isso em um shell script POSIX-ly correto, ou se é um bug no shell do OpenBSD? Além disso, o que significa "erro" no texto POSIX vinculado acima?
Informações extras: Os shells do OpenBSD executarão echo ok
ambos com e sem set -e
no comando
eval ! true || echo ok
Meu código original parecia
set -e
if eval "$string"; then
echo ok
else
echo not ok
fi
que não sairia not ok
com string=false
o uso dos shells do OpenBSD (ele terminaria), e eu não tinha certeza se era por design, por engano ou por mal-entendido, ou qualquer outra coisa.
O fato de nenhum outro shell precisar dessa solução alternativa é uma forte indicação de que é um bug no OpenBSD ksh. Na verdade, ksh93 não mostra esse problema.
Que haja um
||
na linha de comando deve evitar a saída do shell causada por um código de retorno de 1 no lado esquerdo dele.O erro de um built-in especial deve causar a saída de um shell não interativo de acordo com POSIX, mas isso nem sempre é verdade. Tentar
continue
sair de um loop é um erro econtinue
é um built-in. Mas a maioria dos shells não sai em:Um builtin que emite um erro claro, mas não sai.
Assim, a saída
false
é gerada pelaset -e
condição e não pela característica interna do comando (eval
neste caso).As condições exatas em que
set -e
deve sair são bem mais difusas no POSIX.[desculpe se esta não for uma resposta real, vou atualizá-la quando chegar a ela]
Dei uma olhada no código fonte e minhas conclusões são:
1) É um bug/limitação, nada filosófico por trás disso.
2) A "correção" do fork portátil do ksh (
mksh
) do OpenBSD é muito ruim, apenas piorando as coisas, sem realmente corrigi-lo:Novo bug, diferente de todos os outros shells:
Ainda não foi realmente corrigido:
Você pode substituir
bash
acima pordash
,zsh
,yash
,ksh93
, etc.