In der Linux Shell (Bash) gibt es einige Möglichkeiten, Rechenoperationen (auch in Skripten) auszuführen. Ich habe mir drei heraus gepickt, die üblicherweise auf jedem Linuxsystem schon vorhanden sind, und werde sie an Hand von Beispielen vergleichen.
- bash builtin
- bc
- (g)awk
Rechnen mit der Bash selbst
Einfache Rechenoperationen mit Ganzzahlen kann die Bash auch selbst ausführen.
echo $(( (23-2)*2/3 ))
Zu beachten: die doppelten runden Klammern bedeuten "hier wird gerechnet".
Negative Zahlen und Variablen sind auch kein Problem.
var=34; echo $(( $var/-3 ))
Fließkommazahlen oder Rundung kennt die Bash aber nicht. Alles, was hinter dem (nicht vorhandenen) Komma käme, wird einfach abgeschnitten. Jede Zahl wird zum Integer.
Für einfache Berechnungen ist das ausreichend, wenn es genauer sein soll, ist eine andere Methode erforderlich.
Rechnen mit bc
An sich ist bc ein interaktives Programm, aber mit
echo oder dem
here string kann auch in Skripten gerechnet werden.
echo "44/3" | bc -l
bc -l <<< "44/3"
Sehr bequem kann mit der Option
scale die Anzahl der Nachkommastellen angepasst werden:
echo "scale=2; 44/3" | bc -l
bc -l <<< "scale=2; 44/3"
Ergebnis: 14.66
Pfui, bc rundet nicht korrekt. Gawk tut das (siehe weiter unten)
Ganz einfach ist das Übergeben von Variablen an bc:
var=44; echo "scale=4; $var /3" | bc -l
var=44; bc -l <<< "scale=4; $var /3"
Zu beachten: damit die Variable aufgelöst werden kann, müssen die umschließenden Anführungszeichen doppelte sein.
Rechnen mit (g)awk
Gawk ist recht vielseitig und kann in der Shell (in Skripten) auf unterschiedliche Weise für Berechnungen aufgerufen werden.
echo | gawk '{print 44/3}'
gawk 'BEGIN {print 44/3}'
gawk '{print $0/3}' <<< 44
Alle drei Kommandos tun im Endeffekt das Gleiche. Ergebnis: 14.6667
Aha, gawk rundet korrekt.
Die Anzahl der Nachkommastellen kann auf mehrere Arten gesetzt werden:
gawk 'BEGIN {OFMT="%.8f";print ((0.33-2)*2.1)/3.231 }'
gawk 'BEGIN {printf("%.8f\n", ((0.33-2)*2.1)/3.231 ) }'
Also entweder mit dem Setzen der Awkvariable OFMT oder mit Hilfe von printf (gawk hat Wrapper für diverse C-functions). Mehr dazu siehe Manpages von gawk und sprintf. "%.8f" ergibt 8 Nachkommastellen, "%.3f" 3 Nachkommastellen, usw.
Wenn es nur um die Anzahl der Nachkommastellen geht, ist OFMT das Richtige. Sprintf kann noch bedeutend mehr.
Das Übergeben von Shellvariablen an gawk kann tricky sein, oder auch nicht:
var="3.894"; gawk '{print $0/3}' <<< $var
var="3.894"; gawk 'BEGIN {print "'"$var"'"/3}'
Wenn es nur um eine Variable geht, ist die erste Methode (der
here string) eindeutig besser, weil übersichtlicher.
var1="3.894"; var2="65.4"; gawk "BEGIN {print $var2 /3* $var1;}"
Durch das Verwenden von doppelten Anführungszeichen um das gawk Kommando, kann das vereinfacht werden. So löst die Bash die Variablen auf.
var1="3.894"; var2="65.4"; gawk "BEGIN {OFMT=\"%.8f\"; print $var2 /3* $var1;}"
Will man trotzdem OFMT setzen, müssen diese Anführungszeichen mit Backslash escaped werden.
Zum Abschluss noch ein nettes Beispiel, wie mit gawk
spaltenweise addiert werden kann.
cat datei.csv | gawk '{sum+=$3} END{print sum}'
Das bildet die Summe der dritten Spalte der Datei (Feldtrenner in der Datei sind Leerzeichen). Hinweis: "sum" ist ein frei gewählter Variablenname, keine function.
Wichtig dabei: wenn die Spalte Fließkommazahlen enthält, sollte das Kommazeichen unbedingt der Punkt sein.
Wenn nicht, hilft eventuell die gawk Option
--posix, je nachdem, wie eure $LANG Umgebungsvariable ausschaut.
Bei mir ist das
de_DE.UTF-8, mein normales Kommazeichen ist der Beistrich. Wenn ich also...
cat neuedatei.csv | gawk --posix '{sum+=$2} END{print sum}'
...aufrufe, wird Spalte 2 (Kommazeichen ist der Beistrich) richtig addiert, sonst nicht.