Shell-Taschenrechner “bc” und Bash-Rechenfunktionen

Aus EasyLinux 04/2017

Shell-Taschenrechner “bc” und Bash-Rechenfunktionen

© Djayo, sxc.hu

Rechnen in der Shell

Wer regelmäßig mit der Shell arbeitet, muss für kleinere Berechnungen kein grafisches Tool wie KCalc starten: Mit “bc” steht ein leistungsfähiger Rechner fürs Terminal zur Verfügung, und einfache Rechnungen sind auch direkt in der Shell möglich.

Kleine Rechenaufgaben fallen häufig an: Dann gilt es z. B., schnell einige Euro-Beträge zu addieren oder durch Bruchrechnung einen prozentualen Anteil zu bestimmen. Die einfachen Grundrechenarten (Addition +, Subtraktion –, Multiplikation * und Division /) sind direkt in der Shell verfügbar, allerdings nur für Ganzzahlen (ohne Nachkommastellen). Das geht über den Shell-Operator $((...)): Der zu berechnende Ausdruck kommt in doppelte runde Klammern, und am Anfang steht ein Dollar-Zeichen (wie beim Zugriff auf Variablen).

bash$ echo $((3+4))
7
bash$ echo $((42*24))
1008
bash$ echo $((17/3))
5

An der Beispieldivision erkennen Sie, dass die Shell Nachkommastellen weg lässt: Bei der “Division mit Rest” von 17 durch 3 ist das Ergebnis 5, es bleibt ein Rest von 2 (denn 3*5+2=7). Den Rest der Division können Sie mit dem “Modulo”-Operator % ausgeben:

bash$ echo $((17%3))
2

Wollen Sie in komplexeren Ausdrücken Klammern setzen, ist auch das möglich – dadurch entstehen eventuell leicht unübersichtliche Befehle. Im folgenden Aufruf stehen am Anfang drei öffnende Klammern: Die ersten beiden gehören zum Shell-Operator $((...)), die dritte Klammer öffnet die Summe (3+4):

bash$ echo $(((3+4)*2))
14

Wenn Sie Zahlen bereits in Variablen gespeichert haben, können Sie auch direkt im Rechenausdruck darauf zugreifen, ohne den Variablennamen ein weiteres Dollar-Zeichen voranzustellen:

bash$ x=5
bash$ y=10
bash$ echo $((x+2*y))
25

Das klappt auch mit bereits vorhandenen Shell-Variablen, etwa COLUMNS und LINES, welche die Abmessungen des Terminalfensters enthalten – die Anzahl der im Fenster darstellbaren Zeichen erhalten Sie dann über das Produkt:

bash$ echo $COLUMNS $LINES
112 45
bash$ echo $((COLUMNS*LINES))
5040

Variablen ändern

Um einer Variablen einen berechneten Wert zuzuweisen, gehen Sie genau wie bei der sonstigen Arbeit mit Variablen vor – Befehle beginnen mit dem Variablennamen, dann folgt ein Gleichheitszeichen, und dahinter setzen Sie den Rechenausdruck. Der darf auch die zu setzende Variable enthalten: Für die Berechnung arbeitet die Shell dann mit dem bisherigen Wert, und nach dem Kommando enthält die Variable den neuen Wert. Zum Verdoppeln einer Variable x können Sie also das Kommando x=$((2*x)) verwenden:

bash$ echo $x
6
bash$ x=$((2*x))
bash$ echo $x
12

Lassen Sie das führende Dollar-Zeichen weg, können Sie direkt Zuweisungsbefehle (mit Berechnungen) in die Doppelklammern setzen, etwa in der Form

bash$ ((x=x+3))
bash$ echo $x
15

Für häufig benötigte Operationen, die eine Variable verändern und bei der Berechnung den ursprünglichen Wert mit nutzen, gibt es Abkürzungen:

  • ((x+=y)) – addiert y zur Variable x,
  • ((x-=y)) – substrahiert y von der Variablen x,
  • ((x*=y)) – multipliziert y mit der Variablen x,
  • ((x/=y)) – dividiert x durch y,
  • ((x++)) – erhöht den Wert von x um 1 (“Inkrement”),
  • ((x--)) – verringert den Wert von x um 1 (“Dekrement”).

All diesen Befehlen ist gemein, dass x nach dem Ausführen den neu berechneten Wert enthält. Wer eine Programmiersprache beherrscht, kennt diese Zuweisungsbefehle (dort dann ohne die doppelten runden Klammern).

Zahlen dürfen auch negativ sein (und erhalten dann wie üblich ein führendes Minuszeichen), aber wer mit Nachkommastellen arbeiten will, muss auf ein externes Tool zurückgreifen.

Der Taschenrechner “bc”

Für komplexere Rechenaufgaben bietet sich das Programm bc (engl.: basic calculator, deutsch: einfacher Rechner) [1] an, das auf allen Linux-Distributionen vorinstalliert ist. bc bietet einen interaktiven Modus, in dem Sie Rechenbefehle eingeben (und den Sie mit [Strg]+[D] wieder verlassen können), lässt sich aber auch programmieren: Dazu schreiben Sie kleine bc-Skripte, die dann (ähnlich wie Shell-Skripte) vom Rechner abgearbeitet werden. Die Features von bc gehen dann auch weit über ein Rechenprogramm hinaus: Mit Variablen, Funktionen und Fallunterscheidungen steht eine kleine Skriptsprache zur Verfügung – halt mit dem Fokus auf Rechenaufgaben. Der Namensbestandteil “basic” (einfach) ist jedenfalls irreführend.

Auf die Scripting-Möglichkeiten werden wir hier nicht weiter eingehen, sondern nur die elementaren Features vorstellen, die bc bereits zu einem Ersatz für grafische Taschenrechner wie KCalc (KDE) [3] oder Calculator (Gnome) [4] machen.

bc gibt nach dem Start einige Zeilen Text aus, in denen es über Version und Copyright informiert; mit der Option -q können Sie diese Ausgabe unterdrücken, wenn sie stört. Einen Prompt zeigt das Programm nicht an, wartet aber trotzdem in einer leeren Zeile auf die Eingabe eines mathematischen Ausdrucks (oder eines Befehls). Wollen Sie mit Floating-Point-Zahlen rechnen (also Nachkommastellen sehen), verwenden Sie die Option -l.

bash$ bc -l
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
3+4
7

Einfache Rechnungen geben Sie einfach in der üblichen Notation ein, die vier Grundrechenarten sind (wie zu erwarten) über +, –, * und / erreichbar, der Operator für Potenzen ist ^. Mit Klammern erzeugen Sie komplexere Ausdrücke wie etwa

(40.00+17.50+33.33)*1.19
108.0877

Dank einer eingebauten History können Sie ältere Berechnungen wiederholen und (wie in der Shell) auch noch die Zeile bearbeiten, dazu können Sie mit [Pfeil links]+ und [Pfeil rechts] zeichenweise sowie mit [Strg]+[Pfeil links] und [Strg]+[Pfeil rechts] wortweise durch die Zeile wandern; “wortweise” bedeutet dabei, zum Anfang der jeweils vorherigen oder nächsten Zahl zu springen.

Nach dem Beenden von bc (mit [Strg]+[D]) geht die History allerdings verloren, beim nächsten Programmstart geht es mit einer leeren History von vorne los. Wollen Sie mit dem letzten Ergebnis weiter rechnen, können Sie dieses als last in die folgende Formel einbauen:

last+200
308.0877
last-100
208.0877

Alternativ zu last können Sie auch einen einzelnen Punkt (.) verwenden. last ist ein Beispiel für eine Variable, allerdings eine spezielle, die bc nach jeder Berechnung eigenständig aktualisiert. Sie können auch selbst Variablen definieren, indem Sie über den Operator = Werte zuweisen – das eignet sich prima zum Speichern von Zwischenergebnissen. Nach einer Zuweisungsoperation gibt es keine Ergebnisausgabe:

a=40.00+17.50+33.33mwst=19a*(100+mwst)/100
108.08770000000000000000
scale=2a*(100+mwst)/100
108.08

Das Beispiel zeigt eine weitere Spezialvariable: scale enthält die Anzahl der Nachkommastellen, die bc berücksichtigen soll. Wie Sie hier erkennen, rundet bc weder “kaufmännisch” noch “mathematisch” [5], sondern schneidet einfach überzählige Stellen ab. Das Beispiel der Mehrwertsteuerberechnung ist also ungeeignet. Das Problem lässt sich aber mit einem Trick lösen, damit Sie korrekt mit Währungsbeträgen umgehen können: Dazu ist vor dem Runden der Wert 0,005 zu addieren (oder bei negativen Zahlen zu subtrahieren). Das gelingt für obiges Beispiel, indem Sie zunächst mit mehr Nachkommastellen arbeiten, dann die Genauigkeit auf zwei Stellen setzen, den Korrekturwert (0,005 oder -0,005) addieren und dann durch 1,0 teilen:

x=a*(100+mwst)/100scale=2if (x<0) y=(x-0.005)/1.0 else y=(x+0.005)/1.0y
108.09

Für die meisten Zwecke (wenn es nicht gerade um Buchhaltung geht) ist das aber unnötig; stellen Sie einfach über scale eine ausreichende Genauigkeit ein.

Wissenschaftlicher Taschenrechner

Grafische Taschenrechner bieten im wissenschaftlichen Modus auch weitere Funktion, etwa die Quadratwurzel oder die trigonometrischen Funktionen Sinus, Kosinus, Tangens und deren Umkehrfunktionen (Arkussinus, Arkuskosinus, Arkustangens). Einige davon stehen auch in bc zur Verfügung:

  • s(x) berechnet den Sinus (sin x) einer Zahl x,
  • c(x) den Kosinus (cos x),
  • a(x) den Arkustangens (atan x),
  • l(x) den Logarithmus (ln x) zur Basis e = 2,7182818… und
  • e(x) die Exponentialfunktion e^x (exp x).

Die Quadratwurzel ist über sqrt(x) erreichbar: Diese Funktion steht auch zur Verfügung, wenn Sie bc ohne die Option -l starten; auf die übrigen Funktionen müssen Sie dann aber verzichten. Versuchen Sie dennoch, eine davon aufzurufen, antwortet bc mit einer Fehlermeldung und kann kein Ergebnis berechnen:

e(3)
Runtime error (func=(main), adr=5): Function e not defined.

Das liegt daran, dass -l nicht nur die Genauigkeit auf 20 Nachkommastellen setzt, sondern auch eine mathematische Bibliothek einbindet, in der sich die Funktionen befinden.

Andere Zahlensysteme

Standardmäßig verwendet bc für Ein- und Ausgaben das übliche Zehnersystem auf Basis der Ziffern 0 bis 9. Wenn Sie mit Zahlen im Dual-, Oktal- oder Hexadezimalsystem (mit den Basen 2, 8, 16) arbeiten wollen, stellen Sie das über die Variablen ibase (engl. input base, Basis für Eingaben) und obase (engl. output base, Basis für Ausgaben) ein. Das erlaubt ein schnelles Umwandeln in andere Zahlensysteme – um etwa die Hexadezimaldarstellung von 65535 zu berechnen, setzen Sie obase auf 16:

obase=1665535
FFFF

Wollen Sie Berechnungen in einem anderen Zahlensystem durchführen, achten Sie darauf, Ein- und Ausgabe anzupassen:

obase=16; ibase=16ABCDE+11111
BCDEF

Dabei müssen Sie zuerst obase und dann ibase setzen; bei umgekehrter Reihenfolge würde die zweite “16” schon als Zahl in Hexdarstellung interpretiert (und entsprechend zu 1×16 + 6 = 22 ausgewertet, womit Sie die Ausgabe auf das 22er-System umstellen würden, das ungebräuchlich ist).

Die zusätzlichen Ziffern A bis F des Hexadezimalsystems versteht bc nur bei der Schreibweise mit Großbuchstaben.

Beispiel: Verbrauchter Plattenplatz

Als kleine Beispielanwendung zeigen wir Ihnen einen Einzeiler für die Shell, der in einem Ordner die (zusammengefasste) Größe aller Bilddateien berechnet. Um die Gesamtgröße eines Ordners zu bestimmen, würde ein Aufruf von du genügen, für die spezielle Aufgabe ist das Tool nicht geeignet, weil es keine Dateien von der Größenberechnung ausschließen kann.

Für einzelne Dateien können Sie das Programm stat verwenden, um die Größe zu bestimmen: Ohne besondere Optionen gibt es sehr ausführliche Informationen zu Dateien aus (erster stat-Aufruf in Abbildung 1); über den Parameter -c können Sie aber angeben, dass Sie nur die Größe sehen wollen. Der zweite Aufruf in Abbildung 1 zeigt die Variante -c "%s %n", die Größe und Dateiname ausgibt. Um nur die Größe zu sehen, nehmen Sie -c "%s".

Abbildung 1: Das Programm "stat" gibt alle bekannten Informationen zu einer Datei aus &ndash; oder auf Wunsch nur einzelne Angaben wie etwa die Gr&ouml;&szlig;e in Byte ("%s").

Abbildung 1: Das Programm “stat” gibt alle bekannten Informationen zu einer Datei aus – oder auf Wunsch nur einzelne Angaben wie etwa die Größe in Byte (“%s”).

Um in einem Ordner, der viele Bilder im PNG-Format (Dateiendung .png), aber auch weitere Dateien enthält, die Größen aller Bilder aufzulisten, eignet sich der Befehl stat -c "%s" *.png. Jede Dateigröße landet dann in einer separaten Ausgabezeile. Zum Aufaddieren müssen wir diese Werte in eine gemeinsame Zeile verfrachten und Pluszeichen zwischen die Zahlen setzen – das geht mit einem Trick sehr bequem: Das Programm tr erledigt einfache Zeichenersetzungen und kann auch Zeilenumbrüche durch ein anderes Zeichen ersetzen: Das ist genau das benötigte Feature. Mit

tr '\n' '+'

lässt sich die Ausgabe von stat schon fast ins richtige Format umwandeln, allerdings steht am Ende noch ein überflüssiges Plus-Zeichen. Hängen Sie einfach mit echo noch eine Null (0) an, um eine korrekte mathematische Summe zu bilden:

bash$ stat -c "%s" *.png
32058
82823
304365
bash$ stat -c "%s" *.png | tr '\n' '+'; echo 0
32058+82823+304365+0

Jetzt fehlt nur noch die Weiterleitung an bc, um die Summe zu berechnen. Damit die ganze Zeile zur Standardeingabe für bc wird, sind runde Klammern nötig, die eine Gruppe bilden:

bash$ ( stat -c "%s" *.png | tr '\n' '+'; echo 0 ) | bc
419246
Abbildung 2: &Uuml;ber die Kombination von "stat" und "bc" berechnen Sie den summierten Plattenplatzverbrauch f&uuml;r bestimmte Dateitypen.

Abbildung 2: Über die Kombination von “stat” und “bc” berechnen Sie den summierten Plattenplatzverbrauch für bestimmte Dateitypen.

Abbildung 2 zeigt diese Berechnungen für ein Beispielverzeichnis mit anderen Dateien. Tatsächlich hätten wir für dieses Beispiel noch nicht den Taschenrechner gebraucht – die Aufgabe lässt sich auch in der Shell lösen, denn es ist möglich, die Operatoren

  • $((...)) (für Berechnungen) und
  • $(...) (für die Verarbeitung einer Befehlsausgabe als Argument)

zu verschachteln: Der Befehl

echo $(( $( stat -c "%s" *pdf *ps | tr '\n' +; echo 0 ) ))

berechnet die Summe über den Shell-Operator.

“bc” mit “printf” nutzen

bc zeigt Fließkommazahlen standardmäßig mit bis zu 20 Nachkommastellen an, z. B. erscheint das Ergebnis der Berechnung 1/3 in der folgenden Form:

bash$ bc1/3
.33333333333333333333

Sie können die Vorgabe ändern, indem Sie die interne Variable scale auf einen anderen Wert als 20 setzen:

bash$ bc -lscale=21/3
0.33

Alternativ können Sie die Ausgabe von bc auch an die Shell-interne Funktion printf (engl.: print formatted, deutsch: formatiert ausgeben) weiterleiten, die einen so genannten Format-String und beliebig viele Parameter akzeptiert, welche sie dann im gewünschten Format ausgibt. Vor der Verknüpfung von bc und printf zeigen wir Ihnen zunächst, wie printf arbeitet.

Die folgenden Befehle nutzen einige der Features von printf:

bash$ printf "Test-Ausgabe\n"
Test-Ausgabe
bash$ printf "%s\n" "Test-Ausgabe"
Test-Ausgabe
bash$ printf "***%s***\n" "Test-Ausgabe"
***Test-Ausgabe***
bash$ printf "Vorname: %s\nNachname: %s\n" Anton Meier
Vorname: Anton
Nachname: Meier
bash$ printf "%d %f\n" 13 1,12"
13 1,120000
  • Der erste Befehl gibt einfach den Format-String aus, welcher keine Angaben zu Parametern enthält: Damit wird printf als Alternative zum Befehl echo verwendet. Anders als bei echo, muss man hier aber explizit den Zeilenumbruch angeben (\n) – ohne den Umbruch könnten Sie die Ausgabe nicht sehen, weil sie vom neuen Shell-Prompt der Bash überschrieben würde.
  • Mit dem zweiten Befehl nähern wir uns der eigentlichen Funktion von printf: Das erste Argument ist der Format-String "%s\n". An dessen Ende steht wieder der Zeilenumbruch, und %s ist ein Platzhalter für einen String (also Text). Der einzusetzende String folgt als zweites Argument von printf.
  • Im dritten Aufruf sehen Sie, wie Sie um einen Platzhalter herum andere Inhalte im Format-String platzieren können; im Beispiel sind das je drei führende und drei folgende Sternchen. Es ist nicht nötig, Abstand (etwa ein Leerzeichen) zwischen %s und dem sonstigen Text zu lassen.
  • Das vierte printf-Kommando enthält zwei Platzhalter, die (entsprechend der Reihenfolge im Format-String) durch den zweiten und dritten Parameter ersetzt werden. Durch ein zusätzliches \n im Format-String entsteht eine zweizeilige Ausgabe.
  • Mit dem Befehl Nummer 5 verlassen wir die Welt der Strings und arbeiten mit Zahlen: Die kennt printf in zwei Varianten, als so genannte Integer-Zahlen (ganzzahlig, ohne Nachkommastellen) und als Floating-Point-Zahlen (Fließkommazahlen, also Zahlen mit Nachkommastellen). Die Platzhalter für diese beiden Zahlentypen sind %d (dezimal) und %f (floating-point).

Fließkommazahlen gibt printf mit sechs Nachkommastellen aus, also z. B. in der Form 1,230000 – auch dann, wenn die letzten Stellen Nullen sind, wie es etwa bei Währungsbeträgen der Fall ist.

Spracheinstellungen

Wenn Sie bc und printf kombinieren wollen, können Sie das Programm xargs verwenden: Es nimmt die Standardeingabe und erzeugt daraus Argumente für das hinter xargs angegebene Programm. So führt z. B. der Befehl

echo 1 2 3 | xargs printf "%d - %d - %d\n"

zur selben Ausgabe wie

printf "%d - %d - %d\n" 1 2 3

Bei der Verarbeitung von Fließkommazahlen stoßen Sie aber auf ein Problem: bc nutzt bei der Ausgabe den im englischen Sprachraum üblichen Dezimalpunkt als Trenner (also 1.23 statt 1,23), aber printf erwartet Zahlen im deutschen Format mit Dezimalkomma (1,23). Eine Kombination der beiden Befehle verursacht darum zunächst eine Fehlermeldung und eine falsche Ausgabe:

bash$ echo "3/7" | bc -l | xargs printf "%f\n"
printf: .42857142857142857142: expected numeric value
0,000000

Ein Lösungsansatz ist, die Ausgabe zunächst mit dem schon weiter oben erwähnten Tool tr zu korrigieren, also den Punkt durch ein Komma zu ersetzen:

bash$ echo "3/7" | bc -l | tr '.' ',' | xargs printf "%f\n"
0,428571

Alternativ ändern Sie die Spracheinstellungen für die Shell-Sitzung, so dass alle Programme einheitlich mit dem englischen Zahlensystem arbeiten. Das betrifft dann nur printf, denn bc wertet diese Informationen nicht aus.

Welche Spracheinstellungen aktuell gelten, finden Sie mit dem Kommando locale heraus (Abbildung 3). Der Befehl zeigt den Inhalt mehrerer Variablen (LANG und LC_*) an – für die Zahlendarstellungen ist aus der Liste die Variable LC_NUMERIC zuständig. Mit dem Befehl

Abbildung 3: Das Kommando "locale" zeigt alle Variablen an, die Spracheinstellungen bewirken, darunter auch die f&uuml;r Zahlenformate relevante Variable "LC_NUMERIC".

Abbildung 3: Das Kommando “locale” zeigt alle Variablen an, die Spracheinstellungen bewirken, darunter auch die für Zahlenformate relevante Variable “LC_NUMERIC”.

export LC_NUMERIC=C

schalten Sie von der Vorgabe Deutsch (de_DE.UTF-8) auf den englischen Standard (C) um. Danach funktioniert die ursprüngliche Befehlszeile (ohne eingeschobenes tr-Kommando):

bash$ echo "3/7" | bc -l | xargs printf "%f\n"
0.428571

Die Ausgabe verwendet dann auch das englische Format mit Dezimalpunkt. Die folgenden Befehle zeigen noch ein einfacheres Beispiel für Ein- und Ausgaben von printf mit unterschiedlichen Einstellungen in LC_NUMERIC:

bash$ export LC_NUMERIC=C
bash$ printf "%f\n" 1.123
1.123000
bash$ export LC_NUMERIC="de_DE.UTF-8"
bash$ printf "%f\n" 1,123
1,123000

Das Ausgabeformat mit sechs Nachkommastellen können Sie auch bei printf anpassen; um etwa nur zwei Stellen zu sehen, setzen Sie vor das “f” im Format-String noch die Zeichen “.2”:

bash$ printf "%.2f\n" 2,345
2,35

Anders als bc rundet printf dabei korrekt, wie das obige Beispiel zeigt. (Der Aufbau des Format-Strings ist übrigens von den Spracheinstellungen unabhängig.)

“bc” als Web-App

Wenn Sie keinen Rechner mit installiertem bc zur Verfügung haben (was in der Regel bedeutet, dass Sie gerade unter Windows arbeiten, weil bc unter Linux standardmäßig installiert wird), können Sie eine Web-App [2] verwenden: Die Seite lässt Sie mehrere bc-Befehle in einem Textfeld eingeben und führt diese per Klick auf Berechnen aus (Abbildung 4).

Abbildung 4: Auf der ScienceSoft-Webseite finden Sie "bc" als Web-App.

Abbildung 4: Auf der ScienceSoft-Webseite finden Sie “bc” als Web-App.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDF
EasyLinux 04/2017 KAUFEN
EINZELNE AUSGABE
ABONNEMENTS
TABLET & SMARTPHONE APPS
E-Mail Benachrichtigung
Benachrichtige mich zu:

Hinweis: Dieser Artikel ist älter als ein Jahr, enthaltene Informationen sind möglicherweise veraltet.

0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben