GNU/Linux >> Tutoriels Linux >  >> Linux

Pourquoi Bash `(())` ne fonctionne-t-il pas dans `[[]]` ?

La page de manuel GNU bash pour [[..]] explique que l'opérateur exécute une expression conditionnelle et

Renvoie un statut de 0 ou 1 en fonction de l'évaluation de l'expression conditionnelle expression . 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 si arg1 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

Linux
  1. Pourquoi le ~/.bash_profile ne fonctionne-t-il pas ?

  2. Pourquoi Lsdel dans Debugfs ne fonctionne pas ?

  3. Pourquoi ne puis-je pas utiliser Cd dans un script Bash ? ?

  4. Pourquoi le parent Shell Here-document ne fonctionne pas pour la sous-commande dans Dash mais Bash fonctionne?

  5. Pourquoi `exit &` ne fonctionne pas ?

La machine virtuelle CentOS 8 ne fonctionne pas dans VirtualBox 5.2 sur Ubuntu 18.04

chmod ne fonctionne pas

pourquoi le pont linux ne fonctionne pas

Problème(s) d'expression régulière dans Bash :[^negate] ne semble pas fonctionner

pourquoi supprimer l'historique bash n'est pas suffisant?

pourquoi gdb n'aime pas les alias