Warum berechnet die Division in Bash-Arithmetik die meisten Prozentsätze als 0?

15

Der Versuch, eine Bash-Arithmetik für ein Skript durchzuführen, wird jedoch $eerst am Ende aktualisiert. Die Ausgabe spricht für sich.

max=5
for e in $(seq 1 1 $max); do 
    percent=$(( $e/$max*100 ))
    echo "echo $e / $max : = $percent"
done

Tl; DR: Zeigt 1..5 als Prozentsatz an.

Ausgabe :

echo 1 / 5 : = 0
echo 2 / 5 : = 0
echo 3 / 5 : = 0
echo 4 / 5 : = 0
echo 5 / 5 : = 100

Warum ist das?

Cybex
quelle
1
Verwandte Themen: Bash gibt bei der Ausführung von Berechnungen nur eine Ganzzahl als Ausgabe aus, unabhängig von der Eingabe. (Im Gegensatz zu dem hier beschriebenen Problem kann dies jedoch nicht durch eine Neuordnung der Operationen gelöst werden.)
Eliah Kagan,

Antworten:

24

bashkann keine Nicht-Ganzzahl-Arithmetik verarbeiten. Es gibt Ihnen das richtige Ergebnis, solange alle Ausdrücke Ganzzahlen sind. Sie müssen also vermeiden, dass Ihre Berechnung irgendwo einen nicht ganzzahligen Wert enthält.

In Ihrem Fall, wenn Sie auswerten 1 / 5, 2 / 5usw. schafft es die ganze Zahl Null - Werte in bash correspondings auf einige nicht-ganzzahlige Werte und die Ergebnisse kommen aus Null entsprechend zu sein. Der Vorrang von Division und Multiplikation ist derselbe und derselbe Vorrang von Operatoren wird immer von links nach rechts ausgeführt, wenn sie in den Ausdruck eingefügt werden.

Eine Möglichkeit besteht darin, zuerst die Multiplikation und dann die Division durchzuführen, damit bash nie mit nicht ganzzahligen Werten umgehen muss. Der korrigierte Ausdruck lautet:

$ max=5; for e in $(seq 1 1 $max); do percent=$(( $e*100/$max )); echo "echo $e / $max : = $percent"; done
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100
souravc
quelle
1
Der Unterausdruck erstellt 1/5keinen nicht ganzzahligen Wert. Es wird der ganzzahlige Wert erstellt 0, da das Ergebnis der ganzzahligen Division von 1 durch 5 0 ist. Weitere Operationen verwenden den Wert von erfolgreich 0. Dies ist nicht das, was das OP beabsichtigt hat, aber keine Operation erzeugt einen nicht ganzzahligen Wert und keine Operation schlägt fehl.
Eliah Kagan,
@EliahKagan, danke, dass du auf den Fehler hingewiesen hast. Bearbeitet
Souravc
16

Bash kann diese Art von Arithmetik nicht besonders gut ... Hier ist Ihr Problem:

$ echo $((1/5))
0
$ echo $((2/5))
0
$ echo $((4/5))
0
$ echo $((4/5))
0

Wenn Sie nicht ganzzahlige Werte verarbeiten müssen, können Sie verwenden bc

$ max=5; for e in $(seq 1 1 "$max"); do percent=$(bc <<< "scale=1 ; $e/$max*100") ; echo "echo $e / $max : = ${percent%.*}"; done
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100

(Dank an @Arronical für den Hinweis, wie die Ausgabe als Ganzzahl formatiert wird)

Zanna
quelle
Ich werde es mir auf jeden Fall noch einmal ansehen, danke!
Cybex
1
Sie können .0die Ausgabe abschneiden, indem Sie ändern$percent${percent%.*}
abschneiden,
11

Im Gegensatz zu bash bietet awk eine Fließkomma-Arithmetik. Beispielsweise:

$ awk -v max=5 'BEGIN{for (e=1;e<=max;e++) print "echo " e " / " max " : = " 100*e/max}' 
echo 1 / 5 : = 20
echo 2 / 5 : = 40
echo 3 / 5 : = 60
echo 4 / 5 : = 80
echo 5 / 5 : = 100
John1024
quelle
5

Versuchen

percent=$(( $e*100/$max ))

:)

Siehe Abschnitt ARITHMETISCHE BEWERTUNG von:

man bash

Es werden nur Ganzzahlen unterstützt.

Alfred
quelle