Shellskripte speichern eine Abfolge von Kommandozeilenbefehlen. Diese Abfolge legt man sinnigerweise in einem Skript ab und kann sie danach beliebig oft wieder ausführen. Als erstes Beispiel erstellen Sie mit einem Texteditor Ihrer Wahl ein Bash-Skript namens kalender, das im Moment nur den nützlichen Kalender ncal aufruft:
#!/bin/bash ncal
Um das Skript aufrufen zu können, müssen Sie es zunächst mit dem Kommando chmod +x kalender noch ausführbar machen. Das Kommando ./kalender in einem Terminal zeigt nun den laufenden Kalendermonat an, in dem der aktuelle Tag hervorgehoben ist (Abbildung 1).
Sie können dem Programm Ncal Aufrufparameter übermitteln, um sowohl Monat als auch Jahr exakt zu spezifizieren. In den beiden Variablen monat und jahr legen Sie den Wunschzeitraum fest. Die entsprechenden Zuweisungen erfolgen in den Zeilen 3 und 4 von Listing 1.
Listing 1
#!/bin/bash # Variablen monat="8" jahr="2010" # Kalender ncal $monat $jahr
Bei jedem Aufruf listet kalender jetzt den August 2010 auf. Um etwas mehr Entscheidungsfreiheit zu erhalten, erweitern Sie das Kalender-Skript um eine Auswahl für die Monate September, Oktober und November (Listing 2). Als vierter Auswahlpunkt kommt der Eintrag Ende hinzu, mit dem man das Skript verlassen kann. Treffen Sie keine explizite Auswahl, drücken also am Prompt beispielsweise einfach die Eingabetaste, erscheint eine Fehlermeldung Ungültige Auswahl, und das Auswahlmenü erscheint erneut.
Listing 2
#!/bin/bash
# Variablen
PS3="Ihre Wahl: "
monat=""
jahr="2010"
# Auswahl
select monat in September Oktober November Ende
do
case "$monat" in
Ende) echo "Ende."; exit ;;
1) monat="9"; break ;;
2) monat="10"; break ;;
3) monat="11"; break ;;
"") echo "Ungültige Auswahl" ;;
esac
ncal $monat $jahr
done
Diese Variante ist schon recht hübsch (Abbildung 2), aber noch etwas fehlerträchtig. Das Auswerten der Benutzereingaben gestaltet sich bei längeren Listen aufwendig und bildet eigentlich nicht die vorrangige Zielstellung. In den nachfolgenden Beispielen versuchen wir, dieses Manko möglichst weitgehend zu minimieren.
Textbasierte Toolkits
Bevor grafischen Benutzeroberflächen populär wurden, sahen Eingabemasken und Fenster noch etwas anders aus: Sie setzten sich aus ASCII-Zeichen zusammen und richteten sich in Größe und Darstellung an den Eckdaten 80 Zeichen/Zeile und 25 Zeichen/Spalte aus. Heute liefert das Terminalfenster oder die Konsole die Werte für Breite und Höhe.
Die maximale Größe eines Textfensters ermitteln Sie mit dem Aufruf dialog --print-maxsize. Als Ergebnis erhalten Sie die Anzahl von Zeilen und Spalten, die dieses Terminal aktuell darstellen kann. Zur Ermittlung der Werte nutzen Sie alternativ auch das Kommando resize, das beim Aufruf ohne Parameter ebenfalls die aktuellen Werte ermittelt und ausgibt (Abbildung 3).
Anwendungen mit die textbasierten Oberflächen gibt es unter Linux zuhauf. Populäre Beispiele sind der Midnight Commander (mc), der Texteditor vim, das Red-Hat/Fedora-Installationsprogramm anaconda, Debians Paketverwaltungswerkzeug aptitude oder auch Ghost for Linux (g4l), ein Werkzeug zum Sichern und Wiederherstellen von Festplatten und Partitionen .
All diese Anwendungen nutzen zum Darstellen ihrer Oberfläche spezielle Bibliotheken, die viele Anwender nicht kennen, obwohl sie meist bereits auf dem System installiert sind:
- Bei Ncurses [1] handelt es sich um einen Klon der Originalbibliothek Curses aus dem Unix System V Rel. 4.0 (SVr4). Für das frei verfügbare Ncurses gibt es Bindungen unter anderem an C, Perl, Python und Ruby. Die Ncurses-Bibliotheken stecken in den libncurses-Paketen des Systems. Das Paket dialog vereinfacht die Ansteuerung der Ncurses-Bibliotheken, sodass sie Sie auch direkt von der Shell aus nutzen können.
- CDK ([2],[3]) basiert auf der Ncurses-Bibliothek und versteht sich als Zusammenstellung fertiger Bausteine für Textoberflächen. Auf diese Weise will CDK die Verwendung der Ncurses-Bibliothek vereinfachen und die Entwicklungszeit minimieren. Es existieren C- und Perl-Bindungen, verfügbar im Debian-Paket libcdk.
- Newt ("Not Erik's Windowing Toolkit", [4]) wurde ursprünglich von Erik Troan bei Red Hat entwickelt. Newt basiert auf der S-Lang-Bibliothek und beinhaltet Eingabefenster, verschiedene Auswahlboxen, Textfelder und Knöpfe (Buttons). Es gibt Bindungen an die Bash (Paket whiptail) sowie an die Programmiersprachen C, Python, Perl und Tcl. Für Python heißt das fragliche Debian-Paket python-newt.
Alle genannten Bibliotheken haben gemeinsam, dass man mit ihrer Hilfe ohne großen Aufwand einfache und für den Anwender gut handhabbare Eingabefenster erstellen kann. So kann sich der Benutzer ganz auf sein Ziel konzentrieren, ohne dass ihn bunte, blinkende Hinweise und viele Knöpfen ablenken. Weiterhin gehen die Bibliotheken sparsam mit Ressourcen um, was sich insbesondere auf mobilen Geräten und bei Verbindungen zu anderen Rechnern, etwa via SSH, positiv bemerkbar macht.
Dialog basiert auf Ncurses und lässt sich mit wenigen Schritten in eigene Shellskripte integrieren. Whiptail gilt als gleichwertige Alternative zu Dialog, arbeitet jedoch mit dem Newt-Toolkit. Wie immer, liegen auch hier die Unterschiede im Detail: Whiptail beispielsweise löscht nach Verlassen des Dialogfensters automatisch den Bildschirm, Dialog nicht. In Shellskripten findet sich daher nach einem Dialog-Kommando häufig der Aufruf clear.
Kleine Eingabefelder erstellen
Über Parameter und die Standardeingabe lassen sich sowohl der Inhalt als auch das Aussehen der Dialogboxen zusätzlich steuern. Vom Benutzer ausgewählte Menüpunkte, Eingabewerte und eventuell auftretende Fehlercodes übermitteln Dialog und Whiptail über die Standardausgabe und durch den Rückkehrwert des Aufrufs. So lassen sich die Rückmeldungen direkt im aufrufenden Skript weiterverarbeiten. Dialog und Whiptail verfügen über folgende, allgemeine Syntax:
$ dialog Optionen Fensterdetails $ whiptail Optionen Fensterdetails
Die Liste der Optionen fällt recht umfangreich aus, in diesem Beitrag kommt allerdings nur eine davon zum Einsatz – dazu später mehr. Die Fensterdetails spezifizieren das Eingabefeld näher. Der Aufbau folgt dem Schema Fenstertyp "Titel" Breite Höhe.
Der Fenstertyp bezeichnet die Art der Eingabebox – so gibt es beispielsweise einfache Hinweisboxen, Fenster mit einer Entscheidungsfrage und Fenster mit einer kleinen Eingabezeile. Der Titel erscheint in der Kopfzeile des Fensters. Enthält er Leerzeichen, müssen Sie den kompletten Text für den Titel in Anführungszeichen einschließen.
Breite und Höhe geben die Fenstergröße nicht in Pixeln an, sondern als Zeichenanzahl. Belegen Sie beide Parameter jeweils mit dem Wert 0, belegt die Box automatisch nur das absolut notwendige Minimum an Platz auf dem Bildschirm.
Als erstes Beispiel erstellen Sie ein einfaches Fenster mit einer Ja-/Nein-Entscheidungsfrage. Dialog und Whiptail bieten über den Fenstertyp --yesno eine entsprechende Box an. Als Parameter geben Sie lediglich den Text der Fragen sowie Höhe und Breite der Box an (Listing 3). Das Ergebnis zeigt Abbildung 4. Für Whiptail funktioniert der Aufruf identisch, nur dass in diesem Fall der explizite Aufruf von clear entfallen kann. Ganz ähnlich funktioniert der Aufruf einer Box mit einer Mitteilung, die der Benutzer bestätigen muss (Listing 4).
Listing 3
#!/bin/bash dialog --yesno "Lichtabsauger wirklich ausschalten?" 0 0 # Rückgabewert des letzten Kommandos einfangen antwort=$? # Bildschirm löschen clear # Auswertung if [ $antwort = 0 ] then echo "Auswahl: Ja" else echo "Auswahl: Nein" fi
Listing 4
#!/bin/bash dialog --msgbox "Ihre Festplatte ist voll." 0 0 clear
Beide Aufruftypen zusammen lassen sich recht gut in einem Shellskript integrieren, wie Listing 5 demonstriert. Die entsprechende Bildschirmausgabe zeigt Abbildung 5.
Listing 5
#!/bin/bash dialog --yesno "Lichtabsauger wirklich ausschalten?" 0 0 # Rückgabewert einfangen antwort=$? # Bildschirm löschen dialog --clear # Auswertung if [ $antwort = 0 ] then dialog --msgbox "Lichtabsauger wird ausgeschaltet." 6 40 else dialog --msgbox "Lichtabsauger läuft." 6 40 fi clear
Benötigen Sie ein Hinweisfenster ohne explizite Bestätigung, setzen Sie dazu eine Infobox ein. Sie wartet nicht auf eine Reaktion des Benutzers, sondern zeigt lediglich die Information an. Das Skript läuft derweil im Hintergrund weiter:
dialog --infobox "Vorgang läuft ..." 0 0
Rufen Sie in diesem Fall statt Dialog Whiptail auf, nehmen Sie nur ein kurzes Flackern des Terminals wahr. Dabei handelt es sich nicht etwa um einen Fehler: Whiptail stellt die Infobox lediglich dar, hat aber keine weiteren Anweisungen auszuführen. Deshalb löscht es den Bildschirm wieder löscht und beendet sich.



