Comparaison des nombres dans Bash

Je commence à apprendre à écrire des scripts pour le terminal bash, mais je n’arrive pas à comprendre comment faire fonctionner les comparaisons. Le script que j’utilise est:

echo "enter two numbers"; read ab; echo "a=$a"; echo "b=$b"; if [ $a \> $b ]; then echo "a is greater than b"; else echo "b is greater than a"; fi; 

Le problème que j’ai est qu’il compare le nombre à partir du premier chiffre, c’est-à-dire que 9 est plus grand que 10000, mais 1 est plus grand que 09

Comment puis-je convertir les nombres en un type pour faire une vraie comparaison?

Dans bash, vous devriez faire votre vérification dans un contexte arithmétique :

 if (( a > b )); then ... fi 

Pour les shells POSIX qui ne supportent pas (()) , vous pouvez utiliser -lt et -gt .

 if [ "$a" -gt "$b" ]; then ... fi 

Vous pouvez obtenir une liste complète des opérateurs de comparaison avec le help test .

Simple et simple

 #!/bin/bash a=2462620 b=2462620 if [ "$a" -eq "$b" ];then echo "They're equal"; fi 

Vous pouvez consulter cette feuille de calcul si vous voulez plus de comparsions de numéros dans le monde merveilleux de Bash Scripting.

Les entiers ne peuvent être comparés qu’avec:

 -eq # equal -ne # not equal -lt # less than -le # less than or equal -gt # greater than -ge # greater than or equal 

Il y a aussi une bonne chose que certaines personnes ne connaissent peut-être pas:

 echo $(( a < b ? a : b )) 

Ce code imprimera le plus petit nombre sur a et b

Dans Bash, je préfère faire cela car il s’adresse plus comme une opération conditionnelle, contrairement à l’utilisation de (( )) qui est plus arithmétique.

 [[ N -gt M ]] 

A moins que je fasse des choses complexes comme

 (( (N + 1) > M )) 

Mais tout le monde a ses propres préférences. Ce qui est sortingste, c’est que certaines personnes imposent leurs normes non officielles.

Mettre à jour:

Vous pouvez aussi faire ceci:

 [[ 'N + 1' -gt M ]] 

Ce qui vous permet d’append quelque chose que vous pourriez faire avec [[ ]] plus des éléments arithmétiques.

Ce code peut également comparer des flottants. Il utilise awk (ce n’est pas de la pure bash), mais cela ne devrait pas poser de problème, car awk est une commande POSIX standard qui est très probablement livrée par défaut avec votre système d’exploitation.

 $ awk 'BEGIN {return_code=(-1.2345 == -1.2345) ? 0 : 1; exit} END {exit return_code}' $ echo $? 0 $ awk 'BEGIN {return_code=(-1.2345 >= -1.2345) ? 0 : 1; exit} END {exit return_code}' $ echo $? 0 $ awk 'BEGIN {return_code=(-1.2345 < -1.2345) ? 0 : 1; exit} END {exit return_code}' $ echo $? 1 $ awk 'BEGIN {return_code=(-1.2345 < 2) ? 0 : 1; exit} END {exit return_code}' $ echo $? 0 $ awk 'BEGIN {return_code=(-1.2345 > 2) ? 0 : 1; exit} END {exit return_code}' $ echo $? 

Pour le raccourcir, utilisez cette fonction:

 compare_nums() { # Function to compare two numbers (float or integers) by using awk. # The function will not print anything, but it will return 0 (if the comparison is true) or 1 # (if the comparison is false) exit codes, so it can be used directly in shell one liners. ############# ### Usage ### ### Note that you have to enclose the comparison operator in quotes. ############# # compare_nums 1 ">" 2 # returns false # compare_nums 1.23 "<=" 2 # returns true # compare_nums -1.238 "<=" -2 # returns false ############################################# num1=$1 op=$2 num2=$3 E_BADARGS=65 # Make sure that the provided numbers are actually numbers. if ! [[ $num1 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num1 is not a number"; return $E_BADARGS; fi if ! [[ $num2 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num2 is not a number"; return $E_BADARGS; fi # If you want to print the exit code as well (instead of only returning it), uncomment # the awk line below and comment the uncommented one which is two lines below. #awk 'BEGIN {print return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}' awk 'BEGIN {return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}' return_code=$? return $return_code } $ compare_nums -1.2345 ">=" -1.2345 && echo true || echo false true $ compare_nums -1.2345 ">=" 23 && echo true || echo false false 

J’ai résolu ce problème en utilisant une petite fonction pour convertir les chaînes de version en valeurs entières simples pouvant être comparées:

 function versionToInt() { local IFS=. parts=($1) let val=1000000*parts[0]+1000*parts[1]+parts[2] echo $val } 

Cela fait deux hypothèses importantes:

  1. L’entrée est une ” chaîne normale de SemVer ”
  2. Chaque partie est comprise entre 0 et 999

Par exemple

 versionToInt 12.34.56 # --> 12034056 versionToInt 1.2.3 # --> 1002003 

Exemple de test pour savoir si la commande npm répond à une exigence minimale …

 NPM_ACTUAL=$(versionToInt $(npm --version)) # Capture npm version NPM_REQUIRED=$(versionToInt 4.3.0) # Desired version if [ $NPM_ACTUAL \< $NPM_REQUIRED ]; then echo "Please update to npm@latest" exit 1 fi 

Si vous avez des flotteurs, vous pouvez écrire une fonction et ensuite l’utiliser

 #!/bin/bash function float_gt() { perl -e "{if($1>$2){print 1} else {print 0}}" } x=3.14 y=5.20 if [ $(float_gt $x $y) == 1 ] ; then echo "do stuff with x" else echo "do stuff with y" fi