959 Stimmen

Wie kann ich Zahlen in Bash vergleichen?

Ich kann numerische Vergleiche nicht zum Laufen bringen:

echo "Geben Sie zwei Zahlen ein";
read a b;

echo "a=$a";
echo "b=$b";

if [ $a \> $b ];
then
    echo "a ist größer als b";
else
    echo "b ist größer als a";
fi;

Das Problem ist, dass es die Zahl ab der ersten Stelle vergleicht, d.h. 9 ist größer als 10, aber 1 ist größer als 09.

Wie kann ich die Zahlen in einen Typ umwandeln, um einen richtigen Vergleich durchzuführen?

13voto

LC-datascientist Punkte 1614

Die Klammern (z.B. [[ $a -gt $b ]] oder (( $a > $b ))) reichen nicht aus, wenn Sie auch Gleitkommazahlen verwenden möchten; es würde einen Syntaxfehler melden. Wenn Sie Gleitkommazahlen oder eine Gleitkommazahl mit einem Ganzzahl vergleichen möchten, können Sie (( $(bc <<< "...") )) verwenden.

Zum Beispiel,

a=2.00
b=1

if (( $(bc <<<"$a > $b") )); then 
    echo "a ist größer als b"
else
    echo "a ist nicht größer als b"
fi

Sie können mehr als einen Vergleich in der if-Anweisung verwenden. Zum Beispiel,

a=2.
b=1
c=1.0000

if (( $(bc <<<"$b == $c && $b < $a") )); then 
    echo "b ist gleich c und kleiner als a"
else
    echo "b ist entweder nicht gleich c und/oder nicht kleiner als a"

Dies ist hilfreich, wenn Sie überprüfen möchten, ob eine numerische Variable (Ganzzahl oder nicht) innerhalb eines numerischen Bereichs liegt.

8voto

Vangelis Tasoulas Punkte 2951

Dieser Code kann auch Gleitkommazahlen vergleichen. Er verwendet AWK (ist nicht rein Bash). Das sollte jedoch kein Problem sein, da AWK ein Standard-POSIX-Befehl ist, der wahrscheinlich standardmäßig mit Ihrem Betriebssystem geliefert wird.

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

Um ihn kürzer für die Verwendung zu machen, verwenden Sie diese Funktion:

compare_nums()
{
   # Funktion zum Vergleichen von zwei Zahlen (Gleitkommazahlen oder Ganzzahlen) unter Verwendung von AWK.
   # Die Funktion druckt nichts, sondern gibt Rückgabecodes 0 (wenn der Vergleich wahr ist) oder 1 (wenn der Vergleich falsch ist) zurück, damit sie direkt in Bash-Einzellinien verwendet werden kann.
   #############
   ### Verwendung ###
   ### Beachten Sie, dass Sie den Vergleichsoperator in Anführungszeichen umschließen müssen
   #############
   # compare_nums 1 ">" 2 # gibt false zurück
   # compare_nums 1.23 "<=" 2 # gibt true zurück
   # compare_nums -1.238 "<=" -2 # gibt false zurück
   #############################################
   num1=$1
   op=$2
   num2=$3
   E_BADARGS=65

   # Stellen Sie sicher, dass die bereitgestellten Zahlen tatsächlich Zahlen sind.
   if ! [[ $num1 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num1 ist keine Zahl"; return $E_BADARGS; fi
   if ! [[ $num2 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num2 ist keine Zahl"; return $E_BADARGS; fi

   # Wenn Sie den Exit-Code auch drucken möchten (anstatt ihn nur zurückzugeben), kommentieren Sie
   # die unten stehende awk Zeile aus und kommentieren Sie die auskommentierte, die zwei Zeilen weiter unten steht.
   #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

8voto

Sue Punkte 97

Wenn Sie Gleitkommazahlen haben, können Sie eine Funktion schreiben und diese dann verwenden. Zum Beispiel,

#!/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 "mache etwas mit x"
else
    echo "mache etwas mit y"
fi

4voto

broofa Punkte 36174

Ich habe das gelöst, indem ich eine kleine Funktion verwendet habe, um Versionszeichenfolgen in einfache Ganzzahlen umzuwandeln, die verglichen werden können:

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

Dies macht zwei wichtige Annahmen:

  1. Der Input ist eine "normale SemVer-Zeichenfolge"
  2. Jeder Teil liegt zwischen 0-999

Zum Beispiel

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

Beispiel zum Testen, ob der npm-Befehl die Mindestanforderung erfüllt...

NPM_ACTUAL=$(versionToInt $(npm --version))  # npm-Version erfassen
NPM_REQUIRED=$(versionToInt 4.3.0)           # Gewünschte Version
if [ $NPM_ACTUAL \< $NPM_REQUIRED ]; then
  echo "Bitte aktualisieren Sie auf npm@latest"
  exit 1
fi

4voto

nakli_batman Punkte 81

Nur um alle obigen Antworten zu ergänzen:

Wenn Sie mehr als einen Ausdruck in einer einzelnen If-Anweisung haben, können Sie etwas Ähnliches wie folgt machen:

if (( $a % 2 == 0 )) && (( $b % 2 != 0));
  then
  echo "Was du tun möchtest"
fi

Hoffentlich hilft das!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X