
Bei meiner Suche heute Morgen ging es darum, wie ich zwei Dezimalzahlen in Bash vergleichen kann, und ich bin auf diese Antwort gestoßen:So vergleichen Sie mit Gleitkommazahlen in einem Shell-Skript. Dieses hier beinhaltet jedoch nichtdiese Antwort hier:
$ [[ ((3.56 < 2.90)) ]]; echo $?
1
$ [[ ((3.56 < 4.90)) ]]; echo $?
0
Wenn man bedenkt, dass die Antwort heruntergevotet wurde und es sich um eine Art ungewöhnlichen Bashismus handelt, ist die Genauigkeit dieser arithmetischen Auswertung vertrauenswürdig?
Antwort1
bash
versteht keine Gleitkommazahlen.
Zitat aus bash
der Manualpage, AbschnittArithmetische Auswertung:
Die Auswertung erfolgt in Ganzzahlen mit fester Breite […].
Also ((3 < 4))
oder ((3 < 2))
sind eigentlich korrekte Rechenausdrücke. Sie können Folgendes eingeben:
$ echo "$((3 < 4)) -- $((3 < 2))"
Ausgabe:
1 -- 0
Gibt aber $ echo $((3.3 < 3.6))
eine Syntaxfehlermeldung zurück. In Ihrem Beispiel vergleichen Sie tatsächlich Zeichenfolgen. Daher einige Beispiele:
$ [[ ((3.56 < 04.90)) ]]; echo $?
Ausgabe:
1
Antwort2
Der Inhalt [[...]]
<
dient zum Zeichenfolgenvergleich.
Also vergleicht [[ 3.56 < 2.90 ]]
oder [[ (3.56 < 2.90) ]]
oder [[ ((3.56 < 2.90)) ]]
oder [[ (((3.56 < 2.90))) ]]
... einfach die 3.56
Zeichenfolge mit der 2.90
Zeichenfolge lexikalisch (und lexikalisch ist beispielsweise „ 3
größer als“ ).10
Für den Vergleich ganzer Zahlen ist es [[ 3 -lt 2 ]]
oder (( 3 < 2 ))
. Für einen Vergleich von Gleitkommazahlen benötigen Sie ksh93
, zsh
oder yash
oder ein externes Dienstprogramm wie awk
oder perl
; bash
das geht nicht.
Sie könnten beispielsweise eine Funktion wie folgt definieren:
compare() (IFS=" "
exec awk "BEGIN{if (!($*)) exit(1)}"
)
Sie können diese beispielsweise wie folgt verwenden:
if compare '1.5*10 < 1e3'; then
echo less
fi
Oder was das betrifft:
if compare '"bar" < "foo"'...
um Zeichenfolgenvergleiche durchzuführen.
Übergeben Sie keine unkontrollierten, von außen bereitgestellten Daten an diese compare
Funktion, da dies eine Sicherheitslücke durch Befehlsinjektion darstellen würde (die Daten werden als awk
Code interpretiert und können beispielsweise awk
damit Befehle ausführen ).system()