Comportamento de "eval" em "set -e" na expressão condicional

9

Considere os comandos

eval false || echo ok
echo also ok

Normalmente, esperamos que ele execute o falseutilitário e, como o status de saída é diferente de zero, execute echo oke echo also ok.

Em todo o POSIX-como conchas que eu uso ( ksh93, zsh, bash, dash, OpenBSD ksh, e yash), este é o que acontece, mas as coisas começam a ficar interessantes, se permitir set -e.

Se set -eestiver em vigor, o OpenBSD she os kshshells (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 falseconstitui "um erro" (se fosse, seria independente de set -eestar ativo).

A maneira de contornar isso parece ser colocar o evalsub-shell,

( eval false ) || echo ok
echo also ok

A questão é se devo fazer isso em um script shell 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 executam os echo okdois 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 saída not okcom string=falseusando as conchas do OpenBSD (seria terminar), e eu não tinha certeza que era por design, por engano ou por mal-entendido, ou qualquer outra coisa.

Kusalananda
fonte
eval falsegera um status diferente de zero, então eu esperaria set -eterminar o script nesse ponto. No caso de ! set -enão se aplica, a !instrução verifica explicitamente o status de saída.
Fcbsd 12/06/19
@fcbsd Você esperaria eval falsefinalizar o script mesmo que faça parte de uma lista AND-OR ou de uma declaração condicional? Eu não faria.
Kusalananda
Não tenho certeza se set -eestá definido se esse é o comportamento correto ... Concordo que faz sentido não terminar em uma declaração condicional.
Fcbsd
tendo jogado um pouco mais, com sh no CentOS 7 - eu diria que esse é o comportamento pretendido para o ksh / sh do OpenBSD ao usar, set -eentão o `()` é a resposta.
Fcbsd

Respostas:

4

O fato de nenhum outro shell precisar dessa solução alternativa é uma forte indicação de que é um bug no OpenBSD ksh. De fato, o ksh93 não mostra esse problema.

O fato de haver 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 um built-in especial deve causar a saída de um shell não interativo de acordo com o POSIX, mas isso nem sempre é verdadeiro. Tentar continuesair de um loop é um erro e continueestá embutido. Mas a maioria das conchas não sai:

continue 3

Um interno que emite um erro claro, mas não sai.

Portanto, a saída ativada falseé gerada pela set -econdição e não pela característica interna do comando ( evalneste caso).

As condições exatas nas quais a set -esaída deve ser bem mais imprecisa no POSIX.

Isaac
fonte
Isso ecoa a resposta que saí da lista de discussão do OpenBSD, mas com mais palavras, obrigado! Vou resolver um relatório de erro adequado e, se nada acontecer, examinarei o código-fonte.
Kusalananda
4

[desculpe se esta não for uma resposta real, eu a atualizarei quando for contornada]

Eu 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" para isso 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:

mksh -ec 'eval "false; echo yup"'
yup

bash -ec 'eval "false; echo yup"'
(nothing)

Ainda não está realmente corrigido:

mksh -ec 'eval "set -e; false" || echo yup'
(nothing)

bash -ec 'eval "set -e; false" || echo yup'
yup

Você pode substituir bashacima, com dash, zsh, yash, ksh93, etc.

mosvy
fonte