Shell-Skripte selbst schreiben (Teil 2)

Verzweigungen und Schleifen

Das Skript aus Listing 14 bildet ein Auswahlmenü mitsamt eines Untermenüs ab. Es setzt die folgenden Anforderungen um:

  • Komfortable Eingabe über die Tastatur mit je einem Tastendruck.
  • Auswerten der Eingabe, sodass fehlerhafte Eingaben nicht auf dem Bildschirm erscheinen.
  • Für jede Auswahl gibt es genau eine Eingabemöglichkeit.

Listing 14

 

#!/bin/bash
while true; do
  # Bildschirm löschen
  clear
  # Hauptmenü
  echo "(1) Punkt 1"
  echo "(2) zum Untermenü"
  echo "(9) Beenden"
  # Auswahl einlesen, einstellig
  read -n1 -p "Aufgabe: " auf
  # Auswertung. Zahlenwerte als String
  # verhindern Fehleranzeigen, falls
  # Buchstaben gedrückt werden
  if [ "$auf" = "1" ]; then
    echo "Punkt 1"
    sleep 5
  elif [ "$auf" = "2" ]; then
    # neue Schleife
    while true; do
      # Bildschirm löschen
      clear
      # Untermenü
      echo "(a) Punkt a "
      echo "(b) Punkt b "
      echo "(z) zurück"
      read -n1 -p "Aufgabe: " umenu
      if [ "$umenu" = "a" ]; then
        echo "Punkt a"
        sleep 5
      elif [ "$umenu" = "b" ]; then
        echo "Punkt b"
        sleep 5
      elif [ "$umenu" = "z" ]; then
        # Zurück zum Hauptmenü
        break
      fi
    done
  elif [ "$auf" = "9" ]; then
    # Skriptende
    break
  fi
done
clear
echo "Skriptende"

Um das Beispiel einfach zu gestalten, besteht jede Funktion nur aus der Zeile echo "Punkt N", deren Ausgabe für jeweils fünf Sekunden auf dem Bildschirm verbleibt. Für das Hauptmenü stehen drei Möglichkeiten bereit, von denen eine das Skript beendet und eine weitere das Untermenü startet. Beim Beenden zeigt das Skript eine abschließende Nachricht an. Das Untermenü enthält wieder drei Punkte, wobei einer zum Rücksprung ins Hauptmenü dient. Zum Löschen des Bildschirms kommt clear zum Einsatz.

Einige der bereits im vorigen Teil des Workshops angesprochenen Techniken finden sich in diesem Programm wieder. Zum Einlesen der Eingabe steht bei read eine Länge der Zeichenkette von 1; der Anwender braucht also nicht mehr [Eingabe] zu drücken.

Um Fehlermeldungen aufgrund nicht numerischer Zeichen bei test zu vermeiden, vergleichen Sie einfach Zeichenketten anstelle numerischer Werte. Drückt der Benutzer eine Taste, die einem Buchstaben zugeordnet ist, erzeugt das keine Fehlermeldung.

Für das Untermenü starten Sie eine zweite While-Schleife, die das Programm ausschließlich über break wieder verlassen kann. Die Nachricht beim Beenden des Skripts schreiben Sie ans Dateiende, wo das Skript bei einem Abbruch der Schleife via break landet. Alternativ wäre es möglich, die Nachricht vor ein exit innerhalb des If-Konstrukts zu setzen.

Ein weiteres Skript (Listing 15) demonstriert, wie Sie einen Wert, der in einer Datei (im Beispiel lang.conf) hinterlegt ist, wieder auslesen und nutzen. Die möglichen Werte lauten de für die deutsche und en für die englische Sprache. Das Skript liest diese Datei beim Programmstart aus, erstellt das Menü mit drei Punkten: je einem zum Einstellen der Sprache und einem zum Beenden. Die Texte für das Menü liegen in deutscher und in englischer Sprache vor, die Auswahl innerhalb der Menüpunkte gelingt mit Klein- wie Großbuchstaben.

Listing 15

 

#!/bin/bash
# Auslesen Spracheinstellungen
sprache=$(cat lang.conf)
# Menütext anzeigen, Aufgabe abfragen
while true; do
  if [ "$sprache" = "de" ]; then
    clear
    echo -e "(a) Punkt 1\n(b) Punkt 2\n(c) Punkt 3\n(s) Spracheinstellungen\n(e) Ende"
    read -n1 -p "Aufgabe: " aufg
  elif [ "$sprache" = "en" ]; then
    clear
    echo -e "(a) first\n(b) second\n(c) third\n(l) Language\n(q) Quit"
    read -n1 -p "Task: " aufg
  else
    echo "Fehler in der Spracheinstellung"
    exit
  fi
  case "$aufg" in
    [aA])
      echo "1"; sleep 5; ;;
    [bB])
      echo "2"; sleep 5; ;;
    [cC])
      echo "3"; sleep 5; ;;
    [sS]|[lL])
      while true; do
        clear
        echo "(1) Deutsch"
        echo "(2) English"
        read -n1 -p "Sprache/Language: " ehcarps
        if [ "$ehcarps" = "1" ]; then
          sprache="de"
          echo $sprache > lang.conf
          break
        elif [ "$ehcarps" = "2" ]; then
          sprache="en"
          echo $sprache > lang.conf
          break
        fi
      done ;;
    [eE]|[qQ])
      exit ;;
  esac
done

Das Einstellen der Sprache erfolgt durch das Auslesen der Konfiguration und das Belegen der Variable sprache. Deren Wert ändern Sie in den Zeilen 35 oder 39. Den neuen Inhalt von lang.conf schreiben Sie in den Zeilen 36 beziehungsweise 40. Das break danach beendet das Menü.

Mehrsprachige Eingaben erfordern den Einsatz eines Case-Konstrukts. Damit bleibt das Skript kompakt und gut zu verstehen. In der Praxis würden Sie die Texte für die Menüs nicht unbedingt in den Shell-Code aufnehmen, sondern aus einer Datei einlesen.

TIPP

Vermeiden Sie einen häufigen Fehler: Anweisungen im Case-Konstrukt erfordern ein doppeltes Semikolon (;;) am Ende.

Funktionen definieren

Funktionen nehmen generische Code-Teile auf, die Sie immer wieder verwenden. Sie bringen sie direkt am Anfang des Skripts unter. Bei der Wahl des Namens für die Funktion haben Sie weitgehend freie Hand. Vermeiden Sie jedoch Namen, die schon als Programm, Skript oder Variable im Einsatz sind – das führt in der Praxis nur zu Verwirrung.

Wählen Sie trotzdem einen bereits als Befehl verwendeten Namen für eine Funktion, gilt es, die Reihenfolge zu bedenken, in der die Shell diesen Namen aufruft: Zuerst sucht sie nach einer Funktion, dann nach einem eingebauten Befehl der Shell und zuletzt nach einem externen Tool.

Den Exit-Code einer Funktion dürfen Sie selbst definieren. Planen Sie, dass das Skript weiterarbeitet, erreichen Sie das mittels return Exit-Code. Soll das Skript hingegen komplett abbrechen, etwa weil die Quelle an Argumenten erschöpft ist, verwenden Sie exit Exit-Code.

Eine Funktion besteht aus dem einleitenden Namen, einer folgenden leeren Klammer () und dem Körper der Funktion, den Sie mit geschweiften Klammern umschließen (Listing 16, erste Definition). Die leere Klammer entfällt, wenn Sie die Funktion mit dem Schlüsselwort function einleiten – das gilt aber nur für die Bash (Listing 16, zweite Definition).

Listing 16

 

#!/bin/bash
# Funktionsdefinition
hallo () {
  echo "Hallo"
  return 0
}
# alternative Funktionsdefinition
function hallo2 {
  echo "Hallo Hallo"
  return 0
}
# Aufruf der Funktionen
hallo
hallo2

Benötigen Sie eine Funktion im laufenden Skript nicht mehr, etwa, weil es nicht mehr sinnvoll ist, sie aufzurufen, so verfahren Sie mit ihr wie mit einer zu überflüssigen Variablen und löschen sie mit unset Funktion.

Raspberry Pi Geek kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Aktuelle Ausgabe

12/2019
RasPi-Alternativen

Diese Ausgabe als PDF kaufen

Preis € 9,99
(inkl. 19% MwSt.)

Stellenmarkt

Neuigkeiten

  • Grußbotschaften

    Mit Sonic Pi zaubern Sie komplexe Sounds, die Sie bei Bedarf sogar noch während des Abspielens modifizieren.

  • Das Runde und das Eckige

    Mit dem MCP4725 ergänzen Sie einen RasPi um einem D/A-Wandler, der bei Bedarf noch weitere Funktionen erfüllt.

  • Alles unter Kontrolle

    Schon ein einfaches Mikrocontrollerboard wie das CY8CKIT-049-42xx bietet erstaunlich viele Möglichkeiten beim Ansteuern von Hardware.

  • Viele Kerne

    Das Spresense Development Board von Sony lässt sich mit der Arduino IDE programmieren und bringt auch ein eigenes Entwickler-SDK mit.

  • Exotische Früchte

    Der aus China stammende Orange Pi positioniert sich mit einem guten Preis und interessanten Features gegen die RasPi-Truppe. Kann er sich auch behaupten?

  • Flexibler Surfer

    Mit dem neuen RasPi 4 setzen Sie einen öffentlichen Webkiosk schnell und kostengünstig auf.

  • Auskunftsfreudig

    Viele Devices, so auch der E.ON-Aura-Controller, verwenden eine Schnittstelle namens REST, um Zustandsdaten zu übermitteln. Mit ein wenig Bastelei lesen Sie diese auch über Ihr Smartphone aus.

  • Doppelt gemessen

    Mit wenig Aufwand und einem Pi Zero realisieren Sie einen mobilen Zweikanal-Spannungsprüfer.

  • Elegant zusammengeführt

    Tizonia streamt Musik von Online-Quellen und lokalen Sammlungen. Die schlanke Architektur macht den Player zur guten Wahl für den Einsatz auf dem RasPi.

  • Kommunikativ

    Nicht jeder traut sich zu, sein eigenes Smartphone zu bauen. Allerdings kann jeder Linux-Nutzer den Raspberry Pi im Handumdrehen zu einem VoIP-Telefon aufrüsten.