Je commence à apprendre à écrire des scripts pour le terminal bash, mais je ne parviens pas à faire en sorte que les comparaisons fonctionnent correctement. Le script que j'utilise est:
echo "enter two numbers";
read a b;
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 est qu’il compare le nombre à partir du premier chiffre, c’est-à-dire que 9 est supérieur à 10, mais que 1 est supérieur à 09.
Comment puis-je convertir les nombres en un type pour faire une vraie comparaison?
En bash, vous devriez faire votre vérification dans contexte arithmétique :
if (( a > b )); then
...
fi
Pour les shells POSIX qui ne prennent pas en charge (())
, 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 help test
.
Simple et clair
#!/bin/bash
a=2462620
b=2462620
if [ "$a" -eq "$b" ];then
echo "They're equal";
fi
Vous pouvez vérifier cette feuille de triche si vous voulez plus de comparaisons de nombres dans le monde merveilleux des scripts Bash.
En bref, 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 pourraient ne pas savoir:
echo $(( a < b ? a : b ))
Ce code imprimera le plus petit nombre parmi a
et b
Dans Bash, je préfère le faire car cela s’adresse davantage à une opération conditionnelle, contrairement à l’utilisation de (( ))
qui est plus arithmétique.
[[ N -gt M ]]
Sauf si je fais des choses complexes comme
(( (N + 1) > M ))
Mais tout le monde a ses propres préférences. Ce qui est triste, c'est que certaines personnes imposent leurs normes non officielles.
Mise à jour:
Vous pouvez également faire ceci:
[[ 'N + 1' -gt M ]]
Ce qui vous permet d’ajouter quelque chose que vous pourriez faire avec [[ ]]
en plus des choses arithmétiques.
Ce code peut également comparer les flottants. Il utilise awk (ce n'est pas du pur bash), mais cela ne devrait pas poser de problème, car awk est une commande POSIX standard livrée très probablement 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 raccourcir l'utilisation, 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 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:
Par exemple
versionToInt 12.34.56 # --> 12034056
versionToInt 1.2.3 # --> 1002003
Exemple permettant de vérifier si la commande npm
est conforme à la configuration minimale requise ...
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 flottants, vous pouvez écrire une fonction puis l’utiliser, par exemple.
#!/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