Hoe kan ik nummers vergelijken in bash?

Ik krijg geen numerieke vergelijkingen die werken:

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;

Het probleem is dat het het nummer van het eerste cijfer op, d.w.z. 9 vergelijkt is groter dan 10, maar 1 is groter dan 09.

Hoe kan ik de nummers in een type converteren om een ​​echte vergelijking te doen?


Antwoord 1, Autoriteit 100%

In Bash, moet u uw cheque in een rekenkundige context :

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

Voor POSIX-shells die niet ondersteunen (()), kunt u -lten -gtgebruiken.

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

U kunt een volledige lijst met vergelijkingsoperators ontvangen met help testof man test.


Antwoord 2, Autoriteit 21%

Zoals dit:

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

Integers kunnen worden vergeleken met deze operators:

-eq # Equal
-ne # Not equal
-lt # Less than
-le # Less than or equal
-gt # Greater than
-ge # Greater than or equal

Zie deze valsgezel .


Antwoord 3, Autoriteit 5%

Er is ook een leuk ding dat sommige mensen misschien niet weten:

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

Deze code drukt het kleinste getal af van aen b


Antwoord 4, autoriteit 3%

In Bash doe ik dit liever omdat het zichzelf meer als een voorwaardelijke bewerking aanpakt, in tegenstelling tot het gebruik van (( )), wat meer rekenkundig is.

[[ n -gt m ]]

Tenzij ik complexe dingen doe, zoals

(( (n + 1) > m ))

Maar iedereen heeft gewoon zijn eigen voorkeuren. Het trieste is dat sommige mensen hun onofficiële normen opleggen.

U kunt dit ook doen:

[[ 'n + 1' -gt m ]]

Hiermee kun je iets anders toevoegen wat je zou kunnen doen met [[ ]]naast rekenkundige dingen.


Antwoord 5

Deze code kan ook floats vergelijken. Het gebruikt AWK (het is geen pure Bash). Dit zou echter geen probleem moeten zijn, aangezien AWK een standaard POSIX-commando is dat waarschijnlijk standaard bij uw besturingssysteem wordt geleverd.

$ 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 $?

Gebruik deze functie om het korter te maken voor gebruik:

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

Antwoord 6

De dingen tussen haakjes (bijv. [[ $a -gt $b ]]of (( $a > $b ))) is niet genoeg als je wilt ook float-nummers gebruiken; het zou een syntaxisfout melden. Als u float-getallen of float-getal met geheel getal wilt vergelijken, kunt u (( $(bc <<< "...") ))gebruiken.

Bijvoorbeeld

a=2.00
b=1
if (( $(bc <<<"$a > $b") )); then 
    echo "a is greater than b"
else
    echo "a is not greater than b"
fi

U kunt meer dan één vergelijking opnemen in het if-statement. Bijvoorbeeld,

a=2.
b=1
c=1.0000
if (( $(bc <<<"$b == $c && $b < $a") )); then 
    echo "b is equal to c but less than a"
else
    echo "b is either not equal to c and/or not less than a"
fi

Dat is handig als u wilt controleren of een numerieke variabele (integer of niet) binnen een numeriek bereik valt.


Antwoord 7

Als je floats hebt, kun je een functie schrijven en die dan gebruiken. Bijvoorbeeld,

#!/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

Antwoord 8

Ik heb dit opgelost door een kleine functie te gebruiken om versiereeksen te converteren naar gewone integer-waarden die kunnen worden vergeleken:

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

Dit maakt twee belangrijke aannames:

  1. De invoer is een “normale SemVer-tekenreeks
  2. Elk deel is tussen 0-999

Bijvoorbeeld

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

Voorbeeld van testen of het commando npmvoldoet aan de minimumvereiste…

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

Other episodes