Menüs und Masken in der Shell nutzen mit Dialog

Aus LinuxUser 03/2014

Menüs und Masken in der Shell nutzen mit Dialog

© Malalena, sxc.hu

Mehr Komfort

Von einfachen Abfragen bis hin zu komplexen Menüs: Mit dem Toolkit Dialog bauen Sie eine grafische Oberfläche für Shell-Skripte, die oft nicht mehr als eine zusätzliche Zeile brauchen.

Eigentlich handelt es sich bei der Shell ja schon um eine Benutzerschnittstelle – aber kaum ein Nutzer fragt Daten noch auf Zeilenbasis ab. Um den Gewohnheiten der modernen Anwender Rechnung zu tragen, gibt es mit Dialog ein textbasiertes GUI-Toolkit, das die Elemente einer grafischen Oberfläche nachbildet.

Die Optik wirkt etwas antiquiert, aber in Sachen Schnelligkeit ist die Technik kaum zu übertreffen. Läuft auf dem System ein X-Server, verschaffen Sie Ihren Nutzern noch etwas mehr Komfort, wenn Sie auf grafische Dialog-Pendants wie Zenity oder Gtkdialog setzen (siehe Kasten “Verwandte”).

Verwandte

Neben dem hier gezeigten Dialog existieren weitere Projekte mit gleichem Zweck. In der Tabelle “Alternativen” finden Sie heraus, in welchem Umfang die anderen Kandidaten die Fenstertypen anbieten. Einige der Alternativen benötigen eine grafische Benutzeroberfläche: Dazu gehören Xdialog [3], Zenity [4], Kdialog [5] und Gtkdialog [6]. Letzteres weicht vom üblichen Muster ab: Hier erstellen Sie XML-Dateien mit den Anweisungen, die das Programm beim Aufruf einliest.

Alternativen

Dialog-Befehl Xdialog Zenity Kdialog
--yesno --yesno --question --yesno
--msgbox --msgbox --warning oder --info --msgbox
--infobox --infobox --passivepopup
--textbox --textbox --textinfo --textbox
--tailbox --tailbox
--pause
--gauge --gauge --progress --progressbar
--form
--inputmenu --2inputsbox/--3inputsbox
--calendar --calendar --calendar --calendar
--timebox --timebox
--inputbox --inputbox --entry --inputbox
--editbox --editbox --textinfo --textinputbox
--dselect --dselect --file-selection --getexistingdirectory
--fselect --fselect --file-selection --getopenfilename/--getsavefilename
--checklist --checklist --list --checklist
--radiolist --radiolist --list --radiolist
--menu --menubox -- list --menu

Masken und Menüs

Möchten Sie Daten vom Benutzer abfragen, bietet sich bei einfachen Zeichenketten der in die Bash eingebaute Befehl read an, der oft in Kombination mit dem Kommando echo zum Einsatz kommt. Möchten Sie den Prompt für die Eingabe abändern, geben Sie über die Option -p einen neuen Text vor (Listing 1).

Über die Option -n (Zeile 4) verhindern Sie das Newline am Ende der Echo-Anweisung. Daher erscheint der Text direkt rechts vom Read-Prompt. Anführungszeichen in der Ausgabe maskieren Sie mittels eines Rückstrichs (“Backslash”), damit diese keinen Einfluss auf das Ergebnis haben. Die beiden Methoden aus Zeile 4 und Zeile 7 erzeugen das gleiche Ergebnis.

Listing 1

#! /bin/sh
echo "---------------------------"
echo "echo -n \"Eingabe: \";read a"
echo -n "Eingabe: ";read a
echo "---------------------------"
echo "read -p \"Eingabe: \" a"
read -p "Eingabe: " a
echo "---------------------------"

Mit der Option -i Text in Kombination mit -e (Readline-Support) geben Sie dem Benutzer schon eine Eingabe am Prompt vor. Etwas komfortabler klappt das mit dem externen Programm Readpreprompt [1]. Für den korrekten Einsatz führen Sie das Kommando in einer Subshell aus (Listing 2, Zeile 3). Das Tool liefert das Ergebnis der Abfrage auf die Standardausgabe. Mit diesem Befehl gestalten Sie leicht Masken für Datenbankanwendungen.

Listing 2

#! /bin/sh
a="Alter Wert"
a=$(readpreprompt "Eingabe: " "$a")
echo $a

Der eingebaute Befehl echo bietet nur wenig Einfluss auf das Format der Ausgabe. Um Zahlenwerte exakt positioniert auf den Bildschirm zu schreiben, hilft Ihnen das der Programmiersprache C entliehene printf. Bei der Ausgabe von Zahlenwerten mit Nachkommastellen nimmt Ihnen der Befehl das Auf- oder Abrunden ab, zudem berücksichtigt er die Spracheinstellungen der Shell.

Der grundsätzliche Aufbau von Printf-Kommandos folgt dem Aufbau printf "%Format" Daten. Die wichtigsten Anweisungen zum Formatieren finden Sie in der Tabelle “Mit Format”. Der Befehl unterscheidet zwischen Komma und Punkt als Dezimaltrenner. Im Ernstfall passen Sie die Variable LC_NUMERIC oder LANG mittels set und unset innerhalb des Skripts an.

Mit Format

Beispiel Erläuterung
%5.2f Fließkommazahl mit fünf Stellen vor und zwei nach dem Trenner
%.10s Zeichenkette mit maximal zehn Zeichen Breite
%X\n Hexadezimalzahl mit Großbuchstaben
%x\n Hexadezimalzahl mit Kleinbuchstaben
%#X\n Hexadezimalzahl mit Großbuchstaben und führendem 0X
%i\n Ganzzahl (Integer)

Einfacher bringen Sie jedoch mittels tr die Eingabedaten gleich auf das richtige Format. Dies integrieren Sie bei Bedarf direkt in die Anweisung (Listing 3, Beispiel 2). Die Anweisungen für Printf schließen Sie immer mit einem Newline (\n) ab. In einigen Fällen erlaubt der Befehl auch Tabulatoren. Die Beispiele in Listing 3 zeigen die wichtigsten Funktionen, Abbildung 1 die Ergebnisse.

Listing 3

#! /bin/bash
# Beispielwerte
a=987,455
b=987.455
c="Das-ist-ein-langes-Wort"
d=30
# Beispiel 1
# Ausgabe Fließkommazahl, Rundung auf 2 Stellen
printf "%5.2f\n" $b
# Beispiel 2
# Ausgabe Fließkommazahl mit "falschem" Dezimaltrenner
printf "%5.2f\n" `echo $a | tr , . `
# Beispiel 3
# Textausgabe auf zehn Zeichen gekürzt
printf "%.10s\n" $c
# Beispiel 4
# Numerische Umwandlungen bei Darstellung:
# Ganzzahl, Hexadezimalzahl, Oktalzahl
printf "%i %X %o\n" $d $d $d
# Beispiel 5
# Numerische Ausgabe Ganzzahl,
# Hexadezimalzahl (Kleinbuchstaben) mit führenden "0x"
printf "%i  %#x\n " $d $d

Abbildung 1: Über Parameter formatieren Sie mittels <code srcset=

printf die Ausgaben von Daten in der gewünschten Form.” width=”208″ height=”209″ /> Abbildung 1: Über Parameter formatieren Sie mittels printf die Ausgaben von Daten in der gewünschten Form.

Beachten Sie eine Besonderheit bei der Ausgabe von Zeichenketten (Strings): Das Leerzeichen dient normalerweise als Trenner. Das macht jedes Wort einer Zeile zu einem eigenen Variablenwert. In Listing 3 erhielten Sie also eine fünfzeilige Ausgabe, stünden im String der Variablen c Leerzeichen anstelle der Bindestriche.

Beim Aufbau von Menüs gehen Sie wie in Listing 4 vor. Besteht die Auswahlliste nur aus wenigen Punkten, verwenden Sie Ziffern zu deren Kennzeichnung. Damit steuern Sie das Skript komfortabel über den Ziffernblock. Gehen Ihnen die Zahlen aus, verwenden Sie stattdessen Kleinbuchstaben. Bei den Test-Anweisungen behandelt das Skript die Funktionsvariable als String: Das vermeidet verwirrende Fehlermeldungen bei der Eingabe von unpassenden Zeichen. Abbildung 2 zeigt das Beispiel in Aktion.

Listing 4

#! /bin/sh
while true; do
  clear
  echo "(1) Funktion A"
  echo "(2) Funktion B"
  echo "(9) Ende"
  echo " "
  echo -n "Funktion auswählen: "; read f
  if [ "$f" = "1" ]; then
    echo "FUNKTION A";sleep 3
  elif [ "$f" = "2" ]; then
    echo "Funktion B";sleep 3
  elif [ "$f" = "9" ]; then
    exit
  fi
done

Abbildung 2: Ein einfaches Menü, das Sie über die vorangestellten Ziffern steuern.

Abbildung 2: Ein einfaches Menü, das Sie über die vorangestellten Ziffern steuern.

Das Beispiel aus Listing 5 (Abbildung 3) zeigt eine Maske zum Bearbeiten von Daten für eine Adressverwaltung. Für den praktischen Einsatz wären noch die Funktionen zum Holen und Sichern der Daten in einer Datenbank notwendig.

Listing 5

#! /bin/sh
# Belegung Beispieldaten
# An diese Stelle würde ein Datenbankzugriff integriert
a="Herr"
b="Pano Garçon"
c="Testsystem 123"
d="90003 Nürnberg"
while true; do
  clear
  echo "-------------------------------------------"
  echo "      Adressbearbeitung"
  echo "------+----------+-------------------------"
  echo "F-Nr. |          |    Wert"
  echo "  1   |  Anrede: | "$a
  echo "  2   |    Name: | "$b
  echo "  3   |  Straße: | "$c
  echo "  4   | PLZ/Ort: | "$d
  echo "------+----------+-------------------------"
  echo "Aktionen: [F-Nr]: Zeile ändern, [s] speichern,"
  echo "[q] Abbruch"
  echo -n "Aktion: ";read wn
  if [ "$wn" = "1" ]; then
    a=$(readpreprompt "Zeile $wn: " "$a")
  elif [ "$wn" = "2" ]; then
    b=$(readpreprompt "Zeile $wn: " "$b")
  elif [ "$wn" = "3" ]; then
    c=$(readpreprompt "Zeile $wn: " "$c")
  elif [ "$wn" = "4" ]; then
    d=$(readpreprompt "Zeile $wn: " "$d")
  elif [ "$wn" = "s" ]; then
    echo "Hier würde in die Datenbank geschrieben werden"
    break
  elif [ "$wn" = "q" ]; then
    exit
  fi
done
echo "-----------------------------"
echo $a
echo $b
echo $c
echo $d

Abbildung 3: Mit wenigen Zeilen Shell-Code haben Sie eine einfach Maske zum Bearbeiten von Daten aus einer Datenbank erstellt.

Abbildung 3: Mit wenigen Zeilen Shell-Code haben Sie eine einfach Maske zum Bearbeiten von Daten aus einer Datenbank erstellt.

Falls Sie PostgreSQL den Shell-Client psql nutzen, löschen Sie das bei der Datenabholung und Variablenbelegung enthaltene führende Leerzeichen. Mittels cut weisen Sie den Wert erst ab dem zweiten Byte der Variablen zu:

b=$(psql -t -c "select name from adressen where orgnr = 1;" | cut -b 2-)

Im Beispiel sprechen Sie die Datenzeilen mit Nummern und die Funktionen mit Buchstaben an. Nach jeder Änderung baut das Skript den Bildschirm neu auf.

Mit Dialog

Das Programm Dialog [2] liegt vielen aktuellen Distributionen bei. Die Anweisungen setzen sich aus Befehlen zum Gestalten der Fenster, für den Typ und aus geometrischen Anweisungen zusammen. Am Anfang der Anweisung zum Gestalten geben Sie den Titel und einen Hintergrundtitel an. Ferner erwarten die Befehl am Ende zwingend Angaben zur Geometrie.

Die Zeiten des Kästchenzählens sind aber dank Dialog vorbei: Wollen Sie keine Angaben für Höhe (Zeilen) und Breite (Zeichen) machen, geben Sie einfach 0 0 an. Das klappt bei den meisten Anweisungen. Das Tool passt die Proportionen dann automatisch an. Listing 6 zeigt den Aufbau des Befehls.

Listing 6

$ dialog --title "Titel" --backtitle "Hintergrundtitel" Weitere Anweisungen 0 0

In den Anweisungen zum Fenstertyp geben Sie an, was in dieser Codezeile passiert. Möchten Sie, dass der Benutzer etwas liest, eingibt oder entscheidet? In der Tabelle “Fenstertypen” finden Sie eine Auswahl an Möglichkeiten.

Fenstertypen

Anweisung Syntax Rückgabewert Darstellung
Ja/Nein-Frage --yesno "Text" Ja: 0, Nein: 1
Nachrichtenbox --msgbox "Text" 0
Infobox --infobox "Text"
Textbox --textbox DateinameHöheBreite 0)
Ende einer Datei anzeigen --tailbox DateinameHöheBreite
Pause --pause "Text" HöheBreiteSekunden
Fortschrittsanzeige --gauge "Text" 0 0
Eingabemenü --inputmenu "Text" HöheBreiteMenühöhe "Menüpunkt1" "Wert1" ... Daten auf die Standardausgabe
Kalender --calendar "Text" 0 0 Datum
Zeitwerte erfassen --timebox "TEXT" 0 0 Zeitangabe
Eingabebox --inputbox "Text" 0 0 "Vorgabe alphanumerische Werte
Mini-Editor --editbox EingabedateiHöheBreite > Ausgabedatei Textdatei
Verzeichnis auswählen --dselect Verzeichnis 0 0 Verzeichnisname
Datei auswählen --fselect VerzeichnisHöheBreite Dateiname mit Pfad

Während die Ja/Nein-Frage und die Nachrichtenbox stets auf eine Eingabe warten, dient die Infobox zur reinen Ausgabe. Im Zusammenhang mit sleep zeigen Sie so Nachrichten für eine bestimmte Zeit an. Anstelle von sleep ließen sich natürlich andere Programme einbinden.

Sie haben die Möglichkeit, die Ja/Nein-Frage um je eine Schaltfläche zu erweitern. Eine Schaltfläche mit eigener Beschriftung erhalten Sie mit folgenden zusätzlichen Parametern:

--extra-button --extra-label "Text"

Beim Betätigen erhalten Sie den Rückgabewert 3. Die zweite Erweiterungsmöglichkeit besteht mit der Hilfe-Fläche --help-button. Sie benötigen hier keine weiteren Angaben zur Beschriftung, der Rückgabewert beträgt 2. Zusammen mit Ja ( ) und Nein (1) erzeugt das Widget also vier Rückgabewerte.

Das kleine Skript aus Listing 7 zeigt die Wirkungsweise. Sie sehen darin, wie Sie eine Schaltfläche abweichend beschriften oder belegen. Der Befehl im ersten Aufruf ist entsprechend ergänzt. Sie finden vor dem Parameter --yesno den zusätzlichen Parameter --ok-label "Text".

Listing 7

#! /bin/sh
while true; do
  dialog --title "Titel" --backtitle "Hintergrundtitel" --help-button --extra-button --extra-label "EXTRA"  --ok-label "Zustimmung" --yesno "FRAGETEXT" 0 0
  dialog --title "Titel" --backtitle "Hintergrundtitel" --msgbox "Rückgabewert: $?" 0 0
  dialog --title "Titel" --backtitle "Hintergrundtitel" --defaultno --yesno "Shellskript beenden?"  0 0
  if [ $? -eq 0 ]; then
    exit
  fi
done

Gleiches gilt analog für die Nein-Schaltfläche (--no-label "Text"), die Ja-Schaltfläche (--yes-label "Text") und die Hilfe (--help-label "Text"). Mit dem vorangestellten --defaultno in der letzten dialog-Anweisung steht die Auswahl nach dem Start auf No.

Bei der Fortschrittsanzeige übermitteln Sie den Prozentwert per Pipe auf das Dialog-Kommando (Listing 8). Das Element eignet sich ebenfalls zur Anzeige von Anteilen an einem Gesamtwert.

Listing 8

#! /bin/sh
prozent=0
while [ $prozent -lt 100 ]; do
  # Erzeugen der Prozent-Angabe
  prozent=$(echo "$prozent + 10" | bc)
  # Der Wert für gauge wird über die Pipe an dialog übergeben
  echo $prozent | dialog --title "Titel" --backtitle "Hintergrundtitel" --gauge "FORTSCHRITTSTEXT" 0 0
  # sleep nur für Demo!
  sleep 1
done

Listing 9 ist “gebrauchsfertig”: Es zeigt die Belegung der Platte durch das Verzeichnis /home an (Abbildung 4). Unübersichtlich gestaltet sich hier das Herauslösen der Werte aus der df-Abfrage. Der Prozentwert erscheint als Balken, der noch freie Speicherplatz im Klartext.

Listing 9

#! /bin/sh
# Prozentuale Belegung aus df -h übergeben
PROZENT=$(df -h | grep "/home" | tr -s ' ' | cut -d' '  -f5 | cut -d% -f1)
FREI=$(df -h | grep "/home" | tr -s ' ' | cut -d' ' -f4)
echo ${PROZENT} | dialog --title "Plattenbelegung von /home " --backtitle "Systemauskunft" --gauge "\n Aktuell freier Plattenplatz: ${FREI}B" 10 50
sleep 5

Abbildung 4: Mit einem Blick sehen Sie, wie voll die Home-Partition gerade ist.

Abbildung 4: Mit einem Blick sehen Sie, wie voll die Home-Partition gerade ist.

Formulare

Benötigen Sie nicht nur einfache Formulare, sondern eine komplexe Eingabemaske, so bietet Dialog auch dafür die passenden Elemente. Sie bewegen sich darin mit den Tabulator- und Pfeiltasten. Anfangs erscheint die Syntax unübersichtlich: Es gilt, viel mit Positions- und Größenangaben zu hantieren.

Listing 10 zeigt ein kleines Skript, welches das Editieren von Daten erlaubt und wie diese wieder zurück in Variablen ablegt, um diese dauerhaft zurückzuschreiben. Abbildung 5 zeigt, wie sich welche Positions- und Größenangabe des Befehls in der Maske auswirkt.

Listing 10

#! /bin/sh
a="Herr"
b="Meier"
c="Hans"
dialog --title "Titel" --backtitle "Kundendaten" --ok-label "Speichern" --stdout --form "Kartei"  10 60 3 "Anrede  " 1 1 "$a" 1 15 30 0 "Name " 2 1 "$b" 2 15 30 0 "Vorname  " 3 1 "$c" 3 15 30 0 > ausgabe.txt
a=$(cat ausgabe.txt | head -1)
b=$(cat ausgabe.txt | head -2 | tail -1)
c=$(cat ausgabe.txt | head -3 | tail -1)
rm ausgabe.txt
dialog --title "Titel" --backtitle "Hintergrundtitel" --msgbox "Gespeicherte Werte: \n $a \n $b \n $c " 0 0

Abbildung 5: Positions- und Größenangaben für die Elemente des Formulars.

Abbildung 5: Positions- und Größenangaben für die Elemente des Formulars.

Damit das Umleiten der Ausgabe in eine Datei klappt, setzen Sie vor --form zwingend die zusätzliche Anweisung --stdout ein. In der Nachrichtenbox (msgbox) verwenden Sie das Zeichen für ein Newline (\n), um den Wert jeder Variablen in einer neuen Zeile auszugeben.

Formulare mit der Funktion inputmenu benötigen weniger Größen- und Positionsparameter, jedoch erhalten Sie am Ende nicht die Daten sämtlicher Felder. Je Dialog-Aufruf besteht zudem nur die Möglichkeit, ein einzelnes Feld zu ändern.

Die Ausgabe umfasst die Aktion (RENAMED), den Feldbezeichner und die Daten. Damit die Ausgabe funktioniert, müssen Sie wie zuvor bei --inputmenu die Option --stdout setzen. Das Nachbearbeiten der Daten erfolgt mit cut (Listing 11).

Listing 11

#! /bin/sh
neuwert=$(dialog --title "Titel" --backtitle "Hintergrundtitel" --stdout --inputmenu "MENÜÜBERSCHRIFT" 17 60 15 "Zeile-1 >" "Wert 1" "Zeile-2 >" "Wert 2" "Zeile-3 >" "")
spalte=$(echo $neuwert | cut -d \> -f 1 | cut -b 9-)
eintrag=$(echo $neuwert | cut -d \> -f 2 | cut -b 2-)
dialog --title "Titel" --backtitle "Hintergrundtitel" --msgbox "Gespeicherte Werte: \n $neuwert \n $spalte \n $eintrag " 0 0

Wichtig ist, dass Sie als Feldbezeichner ein zusammenhängendes Wort ohne Leerzeichen verwenden. Bei Datenbanken bietet sich dazu der entsprechende Feldname an. Auf diese Weise fällt es leicht, eine SQL-Anweisung mit den passenden Variablen zu versehen.

Eine komfortable Möglichkeit zur Eingabe eines Datums bietet die Funktion --calendar. Beim Aufruf sehen Sie den aktuellen Monat, in der linken Spalte die Kalenderwoche. Mit den Cursor- und Bild-auf/ab-Tasten wechseln Sie zu einem anderen Datum. Mit dem Betätigen der Schaltfläche OK gibt das Widget den vorher markierten Wert aus.

Um eine Variable zu belegen, lenken Sie wieder über --stdout die Ausgabe um. Weil Dialog die Teile des Datums mit einem Schrägstrich unterteilt, ersetzen Sie mittels tr diese durch den hierzulande üblichen Punkt. Das Listing 12 zeigt, wie ein entsprechendes Skript aufgebaut ist. Ein Bild dazu finden Sie in der Tabelle “Fenstertypen”.

Listing 12

#! /bin/sh
a=$(dialog --title "Titel" --backtitle "Hintergrundtitel" --stdout --calendar "TEXT" 0 0 | tr \/ .)
dialog --title "Titel" --backtitle "Hintergrundtitel" --msgbox "gewähltes Datum: $a " 0 0

Zeitwerte erfassen Sie mittels --timebox. Um den Eingabewert zu übernehmen, schalten Sie wieder --stdout vor. Das Fenster zeigt die Zeit des Aufrufs an. Wollen Sie abweichende Werte eingeben, springen Sie mit den Pfeiltasten in die Eingabefelder und geben andere Daten ein.

Beliebige alphanumerische Werte erfassen Sie in einer Eingabebox (--inputbox). Das Belegen einer Variablen innerhalb eines Skripts geschieht mittels vorangestelltem --stdout. Sie haben die Möglichkeit, eine editierbare Vorgabe zu übergeben. Der Vorgang passt in eine Zeile:

a=$(dialog --title "Titel" --backtitle "Hintergrundtitel" --stdout --inputbox "EINGABEÜBERSCHRIFT" 0 0 "VORGABE")

Kleinere Textdateien bearbeiten Sie bei Bedarf in einem Mini-Editor (--editbox). Dabei übergeben Sie als Argument den Namen der Datei. Existiert diese nicht, legen Sie sie mit touch an. Den eingegebenen oder geänderten Text schreiben Sie in eine andere Datei zurück oder hängen ihn an diese an.

Geben Sie für das Fenster die Höhe und Breite an, damit das innere Fenster nicht die Überschrift verdrängt. Wiederum müssen Sie --stdout vorschalten, damit Ihre Eingaben nicht auf der Standard-Fehlerausgabe landen. Sie benötigen nur eine einzige Zeile Shell-Code:

dialog --title "Titel" --backtitle "Hintergrundtitel" --stdout --ok-label "Speichern" --editbox text.txt 20 75  > neu.txt

Das Auswählen von Verzeichnis und Dateiname im Skript erledigen Sie mit --dselect und --fselect. Meist kommen beide in Kombination zum Einsatz. Es empfiehlt sich, für unkundige Benutzer einen Hinweis zum Bedienkonzept anzubringen. Die Auswahl eines Verzeichnisses, das sich auf der gleichen Ebene befindet wie die Vorgabe, erfolgt zunächst über die Pfeiltasten sowie anschließendes Drücken der Leertaste.

Mit --fselect wählen Sie im linken Fensterteil die Pfadangabe, drücken zwei Mal die Leertaste, und erledigen in der rechten Hälfte die Auswahl der Datei. Zwischen den Bereichen wechseln Sie über den Tabulator, innerhalb eines Bereiches navigieren Sie mit den Pfeiltasten.

Das untere Feld erlaubt die manuelle Eingabe. Wenn sich der Cursor darin befindet, springen Sie einfach mit dem Löschen der rechts stehenden Pfadangaben in die nächsthöhere Verzeichnishierarchie zurück (Abbildung 6). Ein Beispiel für die Auswahl von Verzeichnis und Datei finden Sie in Listing 13.

Listing 13

#!/bin/sh
a=$(echo $HOME)
while true
do
  a=$(dialog --title "Titel" --backtitle "Hintergrundtitel" --stdout --fselect $a 0 0)
  dialog --title "Titel" --backtitle "Hintergrundtitel" --defaultno --yesno "$a Übernehmen"  0 0
  if [ $? -eq 0 ]; then
    break
  fi
done

Abbildung 6: Entsprechende Widgets erleichtern die Auswahl von Verzeichnis und Datei.

Abbildung 6: Entsprechende Widgets erleichtern die Auswahl von Verzeichnis und Datei.

Eine Mehrfachauswahl bauen Sie mit --checklist auf. Als Ergebnis erhalten Sie das oder die Kennzeichen (Marke) des jeweiligen Eintrags, welche in Anführungszeichen gefasst sind. Als Feldtrenner fungiert das Leerzeichen. Jedem Eintrag geben Sie den Status mit: on steht hier für markiert, off für nicht markiert.

Die Angaben für Höhe (Zeilen), Breite (Zeichen) und Auswahlhöhe (Zeilen) geben Sie vor. Der Wert für die Auswahlhöhe darf hierbei der tatsächlichen Zahl der Wahlmöglichkeiten gleichen. Passt nicht alles in das Fenster, so gibt es die Möglichkeit zu scrollen. Listing 14 zeigt den Code zusammen mit tr, welches die Anführungszeichen entfernt.

Listing 14

#!/bin/sh
a=$(dialog --title "Titel" --backtitle "Hintergrundtitel" --stdout --checklist "AUSWAHLÜBERSCHRIFT" 10 40 3 MARKE-1 "INFO-1" on MARKE-2 "INFO-2" off MARKE-3 "INFO-3" on)
a=$(echo $a | tr -d \")

Die Einfachauswahl baut sich genauso auf wie die Mehrfachauswahl. Sie verwenden den Fenstertyp --radiolist, setzen nur bei einem einzigen Eintrag den Status on, und erhalten den Marker-Wert ohne die Anführungszeichen. Über die Leertaste wählen Sie den entsprechenden Wert aus:

a=$(dialog --title "Titel" --backtitle "Hintergrundtitel" --stdout --radiolist "AUSWAHLÜBERSCHRIFT" 10 40 3 MARKE-1 "INFO-1" on MARKE-2 "INFO-2" off MARKE-3 "INFO-3" off)

Auf diese Weise setzen Sie eine Datensatz-Auswahl für eine Bearbeitungsmaske um. Dabei erstellt das Skript die Auswahl dynamisch aus der Datenabfrage. Die Marke besteht aus der Datensatznummer oder dem eindeutigen Merkmal, mit dem das Skript den Datensatz anschließend für die Maske einliest.

Das Beispiel in Listing 15 zeigt eine SQL-Abfrage mit dem Client Psql für die PostgreSQL-Datenbank. Ziel ist es, die Kundennummer orgnr an den weiteren Teil des Skripts zu übergeben. Die Anweisungen für das Menü mittels --radiolist schreibt das Skript in eine Variable und führt den Code mit eval aus. Für das weitere Gestalten eignen sich je nach Programmierstil die Fenstertypen --form oder --inputmenu.

Listing 15

#!/bin/sh
# Suchmaske für die Datenbankabfrage
sube=$(dialog --title "Kundensuche" --backtitle "Kundendatenverwaltung" --stdout --inputbox "Kundenname eingeben" 0 0 "")
# Prüfen, ob es zutreffende Daten gibt
a=$(psql -t -c "select orgnr from kunden where name = '$sube';")
if [ -z "$a" ]; then
  dialog --title "Kundensuche" --backtitle "Kundendatenverwaltung" --msgbox "Keine passenden Datensätze gefunden! " 0 0
  exit  # oder break, wenn in Schleife!
fi
# Daten für die Einfachauswahl holen und Aufbau Auswahl
#Zähler für den ersten "on"-Status
v=0
teil1=$(echo "a=\`dialog --title \"Kundensuche\" --backtitle \"Kundendatenverwaltung\" --stdout --radiolist \"gefunden: \" 10 40 3 ")
# Kundennummern ermitteln
for i in $(psql -t -c "select orgnr from kunden where name = '$sube' order by name, vorname, gebdat ;"); do
  if [ $v -eq 0 ]; then
    status="on"
    v=1
  else
    status="off"
  fi
  info=$(psql -t -c "select (name || ' ' || vorname || ' ' || gebdat) from kunden where orgnr = $i;";)
  teil2=`echo $teil2 $i \"$info\" $status`
done
auswahlmaske=$(echo "$teil1 $teil2\`")
echo $auswahlmaske
eval $auswahlmaske
dialog --title "Kundensuche" --backtitle "Kundendatenverwaltung" --msgbox "Datensatz Nr. $a ausgewählt " 0 0

Menüs zur Programmsteuerung gelingen mit dem Fenstertyp --menu. Er gibt eine Marke aus, die Sie anschließend auswerten. Wie bei fast allen anderen Wertübergaben schalten Sie auch hier --stdout vor den Fenstertyp. Ein Beispiel dazu zeigt Listing 16.

Listing 16

#!/bin/sh
while true; do
  a=`dialog --title "TITEL" --backtitle "HINTERGRUNDTITEL" --stdout --menu "MENÜÜBERSCHRIFT" 0 0 0 1 "ERSTE" 2 "ZWEITE" 9 "ENDE"`
  if [ $a -eq 1 ]; then
    dialog --title "Titel" --backtitle "Hintergrundtitel" --msgbox "Erster Eintrag gewählt" 0 0
  elif [ $a -eq 2 ]; then
    dialog --title "Titel" --backtitle "Hintergrundtitel" --msgbox "Zweiter Eintrag gewählt" 0 0
  elif [ $a -eq 9 ]; then
    dialog --title "Titel" --backtitle "Hintergrundtitel" --no-label "Programmende" --yes-label "Weitermachen" --yesno "Programmende ?" 0 0
    if [ $? -eq 1 ]; then
      break # oder exit
    fi
  fi
done

Fazit

Möchten Sie Ihre Shell-Skripts mit einer benutzerfreundlichen Oberfläche aufwerten, so finden Sie alles dazu Notwendige im Fundus von Dialog. Benötigen Sie nur einfache Abfrage, dann profitieren Sie sogar von den Vorteilen bereits vorgefertigter Bausteine. Andernfalls stellt sich vermutlich ohnehin die Frage nach einer Alternative zum Shell-Code. 

Der Autor

Harald Zisler beschäftigt sich seit vielen Jahren mit FreeBSD und Linux. Zu Technik- und EDV-Themen verfasst er Artikel und Bücher. Sein neuestes Werk ist die 2. Auflage “Computer-Netzwerke”, erschienen bei Galileo Press.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDF
LinuxUser 03/2014 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
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben