Comportement de «eval» sous «set -e» dans l'expression conditionnelle

9

Considérez les commandes

eval false || echo ok
echo also ok

Normalement, nous nous attendrions à ce que cela exécute l' falseutilitaire et, puisque l'état de sortie est différent de zéro, à exécuter ensuite echo oket echo also ok.

Dans tous les POSIX comme des coquilles que j'utilise ( ksh93, zsh, bash, dash, OpenBSD ksh, et yash), ce qui arrive, mais les choses deviennent intéressantes si nous permettons set -e.

Si set -eest en vigueur, OpenBSD shet les kshshells (tous deux dérivés de pdksh) termineront le script lors de l'exécution de eval. Aucun autre obus ne fait ça.

POSIX indique qu'une erreur dans un utilitaire intégré spécial (tel que eval) devrait entraîner la fermeture du shell non interactif. Je ne suis pas tout à fait sûr que l'exécution falseconstitue "une erreur" (si c'était le cas, ce serait indépendant d' set -eêtre actif).

La façon de contourner cela semble être de mettre le evaldans un sous-shell,

( eval false ) || echo ok
echo also ok

La question est de savoir si je dois faire cela dans un script shell POSIX-ly correct, ou s'il s'agit d'un bogue dans le shell d'OpenBSD? En outre, que signifie "erreur" dans le texte POSIX lié à ce qui précède?


Info supplémentaire: les shells OpenBSD exécuteront les echo okdeux avec et sans set -e dans la commande

eval ! true || echo ok

Mon code d'origine ressemblait

set -e
if eval "$string"; then
    echo ok
else
    echo not ok
fi

qui serait pas sortie not okavec l' string=falseaide des coquilles d'OpenBSD (il mettrait fin), et je ne savais pas qu'il était par sa conception, par erreur ou par l' incompréhension, ou autre chose.

Kusalananda
la source
eval falsegénère un statut différent de zéro, je m'attends donc set -eà terminer le script à ce stade. Dans le cas de ! set -ene s'applique pas car l' !instruction vérifie explicitement l'état de sortie.
fcbsd
@fcbsd Vous attendriez-vous eval falseà terminer le script même s'il fait partie d'une liste ET-OU ou d'une instruction conditionnelle? Je ne le ferais pas.
Kusalananda
Je ne sais pas si set -eest défini si c'est le bon comportement ... Je conviens qu'il est logique de ne pas se terminer par une instruction conditionnelle.
fcbsd
après avoir joué un peu plus, avec sh sur CentOS 7 - je dirais que c'est le comportement prévu pour ksh / sh d'OpenBSD lors de l'utilisation set -edonc le `()` est la réponse.
fcbsd

Réponses:

4

Le fait qu'aucun autre shell n'ait besoin d'une telle solution de contournement indique fortement qu'il s'agit d'un bogue dans OpenBSD ksh. En fait, ksh93 ne montre pas un tel problème.

Qu'il y ait un ||dans la ligne de commande doit éviter la sortie du shell provoquée par un code retour de 1 sur le côté gauche de celui-ci.

L'erreur d'un spécial intégré doit entraîner la sortie d'un shell non interactif selon POSIX mais ce n'est pas toujours vrai. Essayer de continuesortir d'une boucle est une erreur, et continuec'est une fonction intégrée. Mais la plupart des obus ne sortent pas:

continue 3

Un intégré qui émet une erreur claire mais ne se ferme pas.

Ainsi, la sortie activée falseest générée par la set -econdition et non par la caractéristique intégrée de la commande ( evaldans ce cas).

Les conditions exactes sur lesquelles set -esortiront sont beaucoup plus floues dans POSIX.

Isaac
la source
Cela fait écho à la réponse que j'ai retirée de la liste de diffusion OpenBSD, mais avec plus de mots, merci! Je vais trier un rapport de bogue approprié, et si rien ne se passe, je regarderai moi-même le code source.
Kusalananda
4

[désolé si ce n'est pas une vraie réponse, je le mettrai à jour quand j'y arriverai]

J'ai jeté un œil au code source et mes conclusions sont les suivantes:

1) C'est un bug / limitation, rien de philosophique derrière.

2) Le "correctif" de la fourche portable de ksh ( mksh) d'OpenBSD est très pauvre, ne faisant qu'empirer les choses, sans vraiment le réparer:

Nouveau bug, différent de tous les autres shells:

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

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

Toujours pas vraiment réparé:

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

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

Vous pouvez remplacer bashci - dessus dash, zsh, yash, ksh93, etc.

mosvy
la source