Considere os comandos
eval false || echo ok
echo also ok
Normalmente, esperaríamos que isso executasse o false
utilitário e, como o status de saída é diferente de zero, executasse echo ok
and 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 set -e
.
Se set -e
estiver em vigor, o OpenBSD sh
e ksh
os shells (ambos derivados de pdksh
) encerrarão o script ao executar o eval
. Nenhum outro shell faz isso.
POSIX dizque um erro em um utilitário especial integrado (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 subshell,
( eval false ) || echo ok
echo also ok
A questão é se devo fazer isso em um script de shell correto para POSIX ou se é um bug no shell do OpenBSD? Além disso, o que significa “erro” no texto POSIX vinculado acima?
Informação extra: 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
qual serianãosaída not ok
usando string=false
os shells do OpenBSD (isso seria encerrado), e eu não tinha certeza se era intencional, por engano ou por mal-entendido, ou qualquer outra coisa.
Responder1
O fato de nenhum outro shell precisar de tal solução alternativa é uma forte indicação de que é um bug no OpenBSD ksh. Na verdade, o ksh93 não apresenta esse problema.
A existência de um ||
na linha de comando deve evitar a saída do shell causada por um código de retorno 1 no lado esquerdo dele.
O erro de umespecialembutido deve causar a saída de um shell não interativode acordo com POSIXmas isso nem sempre é verdade. Tentar continue
sair de um loop é um erro e continue
é um erro interno. Mas a maioria dos shells não sai em:
continue 3
Um builtin que emite um erro claro, mas não sai.
Portanto, a saída ativada false
é gerada pela set -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 confusas no POSIX.
Responder2
[desculpe se esta não é uma resposta real, vou atualizá-la quando chegar a hora]
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 émuitopobre, só piorando as coisas, sem realmente consertar:
Novo bug, diferente de todos os outros shells:
mksh -ec 'eval "false; echo yup"'
yup
bash -ec 'eval "false; echo yup"'
(nothing)
Ainda não foi realmente corrigido:
mksh -ec 'eval "set -e; false" || echo yup'
(nothing)
bash -ec 'eval "set -e; false" || echo yup'
yup
Você pode substituir bash
acima por dash
, zsh
, yash
, ksh93
, etc.