La page de manuel GNU bash pour [[..]]
explique que l'opérateur exécute une expression conditionnelle et
Renvoie un statut de
0
ou1
en fonction de l'évaluation de l'expression conditionnelleexpression
. Les expressions sont composées des primaires décrites ci-dessous dans Expressions conditionnelles Bash.
Mais l'opérateur arithmétique n'est pas une partie des expressions conditionnelles prises en charge (primaires ) à l'intérieur de [[..]]
ce qui signifie que l'expression est forcée de s'exécuter comme une comparaison de chaînes, c'est-à-dire
(( $n < 3))
n'est pas exécuté dans un contexte arithmétique mais tout aussi simple comparaison lexicographique (chaîne) que
[[ 100 < 3 ]]
qui sera toujours vrai, car les valeurs ASCII pour 1
, 0
, 0
apparaître avant 3
Mais à l'intérieur du [[..]]
les opérations arithmétiques sont prises en charge si vous utilisez -lt
, -gt
arg1 OP arg2
OP est l'un des
-eq
,-ne
,-lt
,-le
,-gt
, ou-ge
. Ces opérateurs binaires arithmétiques renvoient vrai siarg1
est égal à, différent de, inférieur à, inférieur ou égal à, supérieur à, ou supérieur ou égal àarg2
, respectivement.
Alors aviez-vous écrit votre expression comme
a=start; n=100; [[ " stop start status " =~ " $a " && $n -lt 3 ]] && echo ok || echo bad
bad
cela aurait fonctionné comme prévu.
Ou même si vous aviez forcé l'utilisation de l'expression arithmétique en préfixant $
avant ((..))
et écrit comme ci-dessous (notez que bash n'a pas de comportement documenté pour $((..))
à l'intérieur de [[..]]
). Le comportement attendu probable est que l'expression arithmétique est développée avant le [[..]]
est évalué et la sortie résultante est évaluée dans un contexte de chaîne comme [[ 0 ]]
ce qui signifie une chaîne non vide.
a=start; n=5; [[ " stop start status " =~ " $a " && $(( $n < 3 )) ]] && echo ok || echo bad
Le résultat aurait toujours l'air mauvais, car l'expression arithmétique à l'intérieur de [[..]]
se décompose en une chaîne unaire expression de comparaison non vide comme
$(( 5 < 3 ))
0
[[ -n 0 ]]
Le résultat de l'évaluation arithmétique 0
(false) est pris comme une entité non nulle par l'opérateur de test et affirme true sur le côté droit de &&
. La même chose s'appliquerait également à l'autre cas, par ex. dites n=1
$(( 1 < 3 ))
1
[[ -n 1 ]]
Pour faire court, utilisez les bons opérandes pour l'opération arithmétique à l'intérieur de [[..]]
.
((
est un "mot-clé" qui introduit l'instruction arithmétique. À l'intérieur de [[
, cependant, vous ne pouvez pas utiliser d'autres instructions. Vous pouvez utilisez des parenthèses pour regrouper les expressions, donc c'est ce que (( ... ))
est :un "double groupe" redondant. Les éléments suivants sont tous équivalents, en raison des précédences de <
et &&
:
[[ " stop start status " =~ " $2 " && (($#<3)) ]]
[[ " stop start status " =~ " $2 " && ($#<3) ]]
[[ " stop start status " =~ " $2 " && $#<3 ]]
Si vous voulez une comparaison d'entiers, utilisez -lt
au lieu de <
, mais vous n'avez pas non plus besoin de tout mettre dans [[ ... ]]
. Vous pouvez utiliser une instruction conditionnelle et une instruction arithmétique ensemble dans une liste de commandes.
{ [[ " stop start status " =~ " $2 " ]] && (($#<3)) ; } || { echo "Usage $0 file_name command"; exit 1;}
Dans ce cas, ... && ... || ...
fonctionnera comme prévu, bien qu'en général ce ne soit pas le cas. Préférez un if
déclaration à la place.
if [[ " stop start status " =~ " $2 " ]] && (($#<3)); then
echo "Usage $0 file_name command"
exit 1
fi