Considérez les commandes
eval false || echo ok
echo also ok
Normalement, nous nous attendrions à ce que cela exécute l' false
utilitaire et, puisque l'état de sortie est différent de zéro, à exécuter ensuite echo ok
et 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 -e
est en vigueur, OpenBSD sh
et les ksh
shells (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 false
constitue "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 eval
dans 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 ok
deux 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 ok
avec l' string=false
aide 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.
eval false
génère un statut différent de zéro, je m'attends doncset -e
à terminer le script à ce stade. Dans le cas de!
set -e
ne s'applique pas car l'!
instruction vérifie explicitement l'état de sortie.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.set -e
est défini si c'est le bon comportement ... Je conviens qu'il est logique de ne pas se terminer par une instruction conditionnelle.set -e
donc le `()` est la réponse.Réponses:
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
continue
sortir d'une boucle est une erreur, etcontinue
c'est une fonction intégrée. Mais la plupart des obus ne sortent pas:Un intégré qui émet une erreur claire mais ne se ferme pas.
Ainsi, la sortie activée
false
est générée par laset -e
condition et non par la caractéristique intégrée de la commande (eval
dans ce cas).Les conditions exactes sur lesquelles
set -e
sortiront sont beaucoup plus floues dans POSIX.la source
[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:
Toujours pas vraiment réparé:
Vous pouvez remplacer
bash
ci - dessusdash
,zsh
,yash
,ksh93
, etc.la source