Einführung: Schnittstelle Kommandozeile Teil 8

von Peter Kelly (critter)

Erstellen von Shell Scripten (scripts) Teil 2

Ein Grund für das Schreiben eines Shell Scripts ist unter anderen, wenn die gleiche Operation an vielen Objekten ausgeführt werden muss. Dafür nehmen wir das erste Objekt und führen an ihm eine Reihe von Befehlen aus wie z. B. Untersuchen, Transformieren, Kopieren, Löschen oder Anderes. Wenn wir mit diesem Objekt fertig sind, springen wir zurück zum Ausgangspunkt, nehmen das nächste Objekt und wiederholen die Prozeduren. Dies machen wir solange, bis alle Objekte abgehandelt sind. Der Ablaufkontrolle dient eine Darstellung, die Schleife genannt wird.

Schleifen

Die bei Weitem am meisten genutzte Schleife ist die for Schleife. Als wir Shell Erweiterung besprochen haben, habe ich sie genutzt, um einen Stapel Dateien umzubenennen. Jetzt erkläre ich, wie das geht.

Die Syntax für eine for Schleife ist:

for {variable} in {set}
do
Befehl 1
:
:
Befehl N
done

Variable kann hier jeder nicht benutzte Variablenname sein, auch ein einfacher Buchstabe i oder x werden oft verwendet.

Set ist ein Satz von Ausdrücken wobei jeweils ein Ausdruck beim Schleifendurchlauf der Variablen zugewiesen wird.

Durch ein Beispiel wird dies klarer.

pic

Diese Konstruktion kann von der Kommandozeile aus eingegeben werden und diese wird solange weitere Eingaben anfordern, bis der Schlüsselbegriff zum Beenden eingegeben wird, in unserem Beispiel der Begriff 'done'.

Jeder Ausdruck aus dem Ausdruckssatz der nach dem in bezeichnet ist wird nacheinander der Variablen i zugewiesen und den Befehlen zwischen do und done unterworfen. Hier gibt es nur einen Befehl und $i wird zum jeweils zutreffenden Ausdruck während des Schleifendurchlaufs erweitert. Während dieses Beispiel nur zeigt, wie eine Schleife verwendet werden kann, ist die Schleife durch eine Liste von Dateinamen, gefolgt von Tests oder Aktionen von größerer praktischer Bedeutung.

Nachstehender Code durchsucht ein Verzeichnis und prüft bei jeder Iteration, ob das jeweilige Objekt eine reguläre Datei ist. Wenn ja, wird der Dateiname mit echo am Bildschirm ausgegeben.

pic

Die if – then Schleife ist notwendig, um Objekte wie Verzeichnisse auszuschließen. Der basename Befehl dient dazu, dem Dateinamen vorstehende Pfadverzeichnisnamen abzuschneiden. Auf diese Weise können umfangreiche Objektlisten untersucht und nur die Objekte ausgewählt werden, mit denen man arbeiten will.

Eine zu untersuchende Objektliste kann so ziemlich alles enthalten. Wenn es sich um Zahlen handelt, können wir einen Bereich angeben.

{5..10} würde die Ganzzahlen (5 6 7 8 9 10) bedeuten und zusätzlich kann ein Schrittintervall angegeben werden.

{5..20..3} ergibt also den Satz von Integers (Ganzzahlen) (5 8 11 14 17 20)

Unter Umständen kommt Ihnen auch einmal ein älteres Script in die Hände, das den Befehl seq benutzt, um mit solchen Zahlenfolgen umzugehen:

for i in $(seq start end step)

Im Gegensatz hierzu ist die Bash Schreibweise {start..end..step} schneller, aber beide sind anwendbar.

Die Bash Variable $@ enthält eine Liste von Argumenten, die dem Script auf der Kommandozeile übergeben werden. Dies kann sehr gut dazu verwendet werden, diese Argumente mit einer Schleife zu durchlaufen. Das ist aber nicht notwendig, weil das Ignorieren der Liste zum selben Ergebnis führt.

pic
pic

Die nächsten beiden Schleifenkonstrukte while & until sind ganz ähnlich.

while [Testbedingung]
do
commands
done

and

until [Testbedingung]
do
commands
done

Der Unterschied besteht darin, dass bei while die Schleife solange durchlaufen wird, bis das Testresultat erfolgreich ist, bei until geht es weiter, wenn das Testresultat nicht erfolgreich ist.

pic

Dies durchläuft die Schleife solange bis das Statement 'string s hat nicht den Wert 'exit'' wahr ist. Dagegen wird bei

pic

die Schleife solange durchlaufen, bis das Statement 'string s hat den Wert 'exit' angenommen' falsch ist.

While Schleifen werden öfters benutzt als until Schleifen, häufig um eine Operation eine bestimmte Anzahl mal zu durchlaufen.

pic

Alle Bash Schleifenkonstrukte können verschachtelt sein und auch andere Konstrukte enthalten.

Manchmal kann es sein, dass während eines Schleifendurchlaufs eine Bedingung eintritt, bei der die Schleife beendet und die Abarbeitung des Scripts wiederaufgenommen werden muss. Für solche Fälle stellt die Bash den break Befehl zur Verfügung. Im Beispiel verwenden wir eine andere Methode für die Schleifenindizierung: Einen Ausdruckssatz von 3 Parametern zur Schleifenkontrolle.

pic

Der erste Ausdruck, i=1, startet die Abzählung, i<=5 gibt den höchstmöglichen Zählerstand an und i++ erhöht den Zähler um 1 bei jedem (Schleifen)durchlauf. Dabei kann der zweite Ausdruck ein beliebiger gültiger Test sein, und der dritte Ausdruck könnte auch i-- sein, was Rückwärtszählen bedeuten würde, oder i+=3 um den Zählerstand bei jeder Iteration um 3 zu erhöhen. Im vorliegenden Script werden die Werte 1, 2 und 3 am Bildschirm ausgegeben.

Wenn Sie nur den aktuellen Durchlauf der Schleife vor Beendigung des Schleifenkörpers anhalten und dann anschließend einen neuen Schleifendurchlauf starten wollen, ist der Befehl continue genau richtig. Dies Beispiel erfasst in einer Schleife den Inhalt eines Verzeichnisses und lässt alle Unterverzeichnisse unberücksichtigt.

pic

Beide Befehle nutzen ein optionales numerisches Argument, das es erlaubt, die Anzahl der eingeschlossenen Schleifenebenen zu spezifizieren, damit man diese auch wieder verlassen kann. Das ist z. B. Break 2, um aus 2 verschachtelten Schleifen zurückzuspringen.

In den vorhergehenden Beispielen wurde jede Bildschirmausgabe durch den echo Befehl erzielt. Das ist zwar einfach in der Anwendung, aber ziemlich beschränkt. Ein nützliches Werkzeug ist das Bash builtin (in die Bash eingebauter Zusatz) printf, das uns die Möglichkeit bereitstellt, Text zu formatieren.

Printf {Format-String} {Argumente}

Dabei ist der Format-String Teil eine Mischung aus normalem Text, der unverfälscht ausgegeben wird, aus Escape Sequenzen (wie \n um ein Zeilenvorschubzeichen auszugeben) und Formatspezifizierungen wie %s um einen Buchstabenstring zu kennzeichnen oder %d für eine Dezimalganzzahl. Die Argumente sind das was Sie drucken wollen.

Die gebräuchlichsten Escape Sequenzen sind:

\b backspace
\f formfeed
\n newline
\t tab
\v vertical tab

Die Formatspezifikationen sorgen für Buchstabenstrings, positive oder negative Ganzzahlen und Fliesskommazahlen mit oder ohne Exponent und darüber hinaus für Hexadezimalzahlen und Oktalzahlen. Machen Sie sich keine Sorgen, wenn Sie einige davon nicht kennen. Vielleicht brauchen Sie sie gar nicht.

Natürlich können Sie dem Befehl auch nur reinen Text, ohne die ausgefallenen Escape Sequenzen oder Formatspezifikationen, übergeben. Aber wenn Sie auf einer Kommandozeile

printf "Hello World"

eingeben, werden Sie feststellen, dass ihr Eingabeprompt ans Ende des Textes verlagert wird. Anders als beim echo Befehl liefert der printf Befehl kein Zeichen für einen neue Zeile und daher bleibt die Stelle, an der der Text eingefügt wird, hinter dem ausgegebenen Text.

printf "Hello World\n"

verhält sich dann aber wie erwartet.

Dies mag zunächst aussehen, als wäre es eine Last, es verbessert jedoch die Gebrauchsmöglichkeiten der Funktion, indem es eine präzisere Kontrolle der Ausgabe ermöglicht.

pic
pic

Zeile 3 initialisiert die Variable x mit dem Wert 0. Das ist nicht wirklich notwendig, ist aber gute Programmierpraxis zur präzisen Kontrolle von Variablen.

Die Schleife in den Zeilen 4 – 7 zählt einfach die Anzahl der Einträge im Verzeichnis.

In Zeile 9 wird dann die Arbeit ausgeführt. Das beginnt mit wörtlichem Text, an den das erste der bereitgestellten Argumente und die Umgebungsvariable $PWD, mit dem gegenwärtigen Verzeichnis, angefügt werden. Das %s veranlasst den Befehl das Argument wie einen Buchstabenstring zu behandeln. Dem folgt das Zeichen für einen Zeilenvorschub und dann wieder wörtlicher Text. Der Zeilenvorschub stellt sicher, dass der nachfolgende Text in einer neuen Zeile darunter ausgegeben wird. Beachten Sie, dass zwischen der neuen Zeile und dem Text kein Leerzeichen steht. Wenn da ein Leerzeichen stünde, wäre es das erste Zeichen am Beginn einer Zeile und würde den Text einrücken. %d holt das nächste Argument, den Dateienzähler $x. Letzterer wird als Ganzzahl ausgegeben. Der Formatstring wird mit einem weiteren Zeilenvorschub abgeschlossen und der gesamte Formatstring wird in Doppelanführungszeichen gesetzt.

Im vorigen Beispiel hatte die Definition der Variablen $x als Ganzzahl (Integer) keine Auswirkung. Das gleiche Ergebnis wäre erzielt worden, wenn $s benutzt und als String ausgegeben worden wäre.

Mit den Formatspezifikationen können Kennzeichnungen (flags) für Modifikationen eingesetzt werden. Diese stehen zwischen dem % und dem flag der Formatspezifikation width.precision.

width bedeutet die Gesamtzahl von Leerzeichen, die der eingefügte Wert einnimmt. Wenn die tatsächliche Anzahl kleiner ist, als die spezifizierte, wird von links aufgefüllt (right justified).

precision ist die Anzahl der Ziffern oder Zeichen, die auszugeben sind. Dies ist von der Formatspezifikation abhängig. Bei einer Zeichenkette ist das die größte Anzahl von Zeichen. Bei Ganzzahlen ist standardmäßig die kleinste Anzahl von Ziffern 1. Bei Fliesskommazahlen ist es die Anzahl von Dezimalstellen.

Ein oder mehrere Flags werden durch Folgendes gesetzt:

Leerzeichen werden positiven Zahlen mit einem Leerzeichen 
vorangestellt und negativen Zahlen mit einem Minuszeichen. - von links auffüllen (left justify) + Präfixzahlen mit einem - oder + Zeichen 0 Zahlen mit Nullen, anstatt mit Leerzeichen auffüllen # Ausgabeart ändern

Wenn Sie wirklich eines brauchen, brauche ich Ihnen sicher nicht zu erklären, wie man es benutzt.

Beginnen Sie mit ein paar Beispielen:

pic
pic

Wenn es mehr Argumente gibt als Formatspezifikationen, dann wird der Formatstring wiederverwendet und fehlende Argumente werden als Null oder leerer String angesehen. Verändern wir z. B. das erste Script zu:

pic

Beim ersten Mal geht alles gut, aber dann gibt es das ungenutzte "/bin" Argument. Der Formatstring wird daher erneut verwendet. Das Script erwartet jedoch einen String und eine Ganzzahl und setzt daher eine Null für das fehlende Argument.

pic

Wenn die Ausgabe der zweiten Zeile wahr wäre, hätten wir ein echtes Problem.

Funktionen

Eine Funktion kann als ein Teilscript verstanden werden. Dabei handelt es sich um einen Codeblock, der durch Aufruf seines Namens ausgeführt wird. Der Funktion können beim Aufruf Argumente, die sie verarbeiten soll, übergeben werden und sie muss vor ihrem Aufruf definiert sein (werden). Aus diesem Grund werden Funktionen üblicherweise am Anfang eines Scripts definiert, sie können aber auch von einer anderen Datei aufgerufen werden. Wenn in einem Script identischer Code an unterschiedlichen Stellen zum Einsatz kommt, sollten Sie die Festlegung einer Funktion erwägen.

Während die Shell ein Script durchläuft erkennt sie Funktionsdefinitionen und speichert die Befehle für die spätere Ausführung. Dies macht den Einsatz von Funktionen in einem Script äußerst effizient für die Programmierung. Eine Funktion kann auch von innerhalb einer Funktion aufgerufen werden.

Das folgende Beispielscript ist vorhanden, wenn der Benutzer root ist. Ein Benutzer, der mit dem su Befehl temporäre root Rechte erworben hat, wird aber nicht erkannt. Um solche Benutzer einzubinden muss auch die $USERNAME Variable geprüft werden.

pic

Für die Argumente, die einer Funktion übergeben werden, wird dieselbe Notation benutzt, wie für Argumente, die einem Script über die Kommandozeile übergeben werden. Man nennt sie positionale Parameter. Die Argumente der Kommandozeile werden während des Ausführens der Funktion temporär gespeichert. Hier ist das erste (und einzige) der Funktion übergebene Argument $USER und es wird von der Funktion als $1 angesprochen. Der zurückgegebene Wert kann untersucht und das Ergebnis der Funktion ermittelt werden. Null bedeutet immer wahr und jede positive Ganzzahl wird als falsch angesehen. Eine Funktion darf so einfach oder so komplex sein, wie Sie wollen, aber sie darf nicht leer sein.

Beim Verarbeiten von Argumenten, die einem Script oder einer Funktion übergeben wurden, ist es oft nützlich, den shift Befehl zu verwenden. Dieser verschiebt alle Argumente um einen oder mehrere Plätze nach links, wodurch der Inhalt von $1 durch jenen von $2 ersetzt wird, $3 geht nach $2 und so weiter. Dies können wir benutzen, um Argumente in einer Schleife nacheinander durchzureichen. Wenn das Argument $1 ein eigenes qualifizierendes Argument enthält, z. B. einen Dateinamen, der mit diesem Argument benutzt werden soll, dann wird die in $2 wiedergefunden. Nach der Ausführung kann dieses Argumentepaar einen weiteren shift Befehl nutzen, um die Argumente die erforderlichen Plätze nach links zu rücken. Dafür könnte der shift Befehl auch mit dem optionalen Parameter shift 2 gesteuert werden.

pic
pic

Das Nützliche an diesem Befehl ist, dass nacheinander Argumente aus $1 an einen Codebereich eines Scripts oder an eine Funktion zur Ausführung übergeben werden können. Die Notwendigkeit, einen Satz von Optionen oder Argumente, die einem Script übergeben werden, zu durchleuchten, hat zum getopts Befehl geführt. Dieser Befehl erleichtert die Syntaxanalyse von Kommandozeilen außerordentlich. Der getopts Befehl akzeptiert eine im Script oder in der Funktion gültige Optionsliste. Er erkennt, dass jede Option mit anschließendem Doppelpunkt ein zusätzliches Argument erfordert, das in der Variablen $OPTARG niedergelegt ist. Dabei wird zunächst bei jeder zugeführten Option das voranstehende – entfernt, bevor es in einer Variablen abgelegt wird, die dem Befehl getopts {Optionen} {var} {Argumente} übergeben wird.

Nehmen wir an, wir sollten ein Script mit der Syntax

myscript -cnh

schreiben

-c [Ziel] kopiere eine Datei ins Zielverzeichnis
-n gib die Anzahl der Dateien aus, die verarbeitet wurden
-h gib einen Hilfetext aus und verlasse das Script

mit dem wir einen Satz von Dateien abzählen oder von dem wir Sicherheitskopien anfertigen wollen und den wir im Argumentbereich der Kommandozeile angeben wollen. Um einen solchen Befehl ausführen zu lassen, könnten wir Code verwenden, der so aussieht:

COUNTING=0
while getopts c:nh options
do
case $options in
  100. DEST=$OPTARG
;;
  n)COUNTING=1
;;
  h)echo "Einsatzmöglichkeiten finden Sie in den zugehörigen Dokumentation."
  exit 0
;;
esac
done

Dies stellt die Funktionalität des Scripts dergestalt bereit, dass uns die Überprüfung des Inhalts der Variablen $COUNTING mitteilt, ob ein Zählen der Dateien vorzusehen ist. Wenn die -c Option angegeben war, dann sagt uns die Variable $DEST - wenn sie definiert ist – dass der Kopiervorgang für die Dateien der Argumentliste ausgeführt werden soll und die Variable enthält auch den Pfad für das Zielverzeichnis.

Der Befehl getopt entfernt die Optionen nicht aus der Kommandozeile, sondern er unterhält einen Index, der zur nächsten Option in der Variablen $OPTIND führt. Wenn wir nach der while Schleife den shift Befehl einsetzen,

shift $(( OPTIND — 1 ))

werden alle Optionen und die, die sie anfordern, entfernt und es bleiben nur die Argumente in den positionalen Parametern $1, $2 .. übrig (die zu verarbeitende Dateiliste).

Wenn Sie Argumente im Script und in Funktionen des Scripts mit dem getopt Befehl verarbeiten lassen wollen, müssen Sie sich dessen bewusst sein, dass die Variable OPTIND nicht automatisch zurückgesetzt wird. Sie sollte daher beim Einstieg in die Funktion zurückgesetzt werden, um sicherzustellen, dass das erste abgerufene Argument auch das erste Argument ist, das der Funktion übergeben wird.

Zenity

Jetzt haben wir einen schönen Satz von Werkzeugen beisammen, mit dem wir anfangen können, unsere Scripte aufzubauen. Schon diese wenigen Routinen reichen aus, um den Code für einige recht anspruchsvolle Hilfsmittel zu erstellen. Dafür brauchen Sie nur Logik, Intuition und Geduld. Unser Werkzeugkasten enthält jetzt zwar Sachen, mit denen wir Scripte für unseren eigenen Gebrauch schreiben können, wenn wir aber Lösungen für allgemeineren Gebrauch bereitstellen wollen, dann sollten wir unsere Scripts etwas benutzerfreundlicher gestalten. Einige der (künftigen) Benutzer sind vielleicht mit der Kommandozeile nicht so vertraut, wie Sie es jetzt sind.

Glücklicherweise können hier einige ausgezeichnete Hilfsmittel aus den Repositories helfen. Wenn Sie PCLinuxOS verwenden sind eines oder mehrere wahrscheinlich bei Ihnen schon installiert. Der Befehl dialog stellt im Terminal einfache pop up Kästchen bereit:

dialog --msgbox 'Hello World!' 8 20

Zeigt eine einfache Nachrichtenbox mit einer Höhe von 8 Zeilen und einer Breite von 20 Spalten. Angezeigt wird die Nachricht "Hello World!" mit einen mausklickfähigen OK Knopf.

Mit kdialog stellt KDE eine ähnliche Möglichkeit zur Verfügung. Hier werden Dialogboxen direkt auf dem Desktop verwendet und die Ergebnisse an das laufende Script zurückgegeben.

Es gibt noch andere Möglichkeiten und alle haben ihre Vor – und Nachteile. Eine häufig genutzte und einfach anzuwendende heißt Zenity. Benutzer von PCLinuxOS können diese in Aktion sehen, wenn sie das ausgezeichnete Hilfsmittel Repo Speed Test von travisn000 laufen lassen. Es ist höchst empfehlenswert, den Text des Scripts zu studieren. Damit können wir einige der Themen, die wir zuletzt behandelt haben und ihr Zusammenspiel mit einem nützlichen Hilfsmittel besser verstehen. Zusätzlich lernen wir dadurch auch noch einige Tricks. Das Script findet man unter /usr/bin/apt-sources-update.sh.

All diese Dialoghilfsmittel sind schon recht verständlich. Noch einfacher wird die Implementierung und die Übersicht hinsichtlich der Möglichkeiten, wenn man den Befehlsnamen gefolgt von –help eingibt. Ich werde einige Möglichkeiten demonstrieren, wie Zenity dafür genutzt werden kann, um Ihre Scripts schmackhafter zu machen und ihnen ein professionelles Aussehen zu geben.

Die Syntax des zenity Befehls ist einfach

zenity options

Mit den Optionen wird der anzuzeigende Dialogtyp gemeinsam mit allen Optionen angezeigt, die zu diesem speziellen Dialog gehören. Die Dialogtypen, die zur Verfügung stehen und die Optionen, sie aufzurufen beinhalten:

--calendar   	  Kalenderdialog anzeigen
--entry      	  Texteingabe-Dialog anzeigen
--error      	  Fehlerdialog anzeigen
--file-selection  Dateiwähler-Dialog anzeigen
--info       	  Info-Dialog anzeigen
--list       	  Listendialog anzeigen
--notification    Benachrichtigung anzeigen
--progress   	  Fortschrittsanzeige-Dialog
--question   	  Fragedialog anzeigen
--text-info  	  Text-Informationsdialog anzeigen
--warning    	  Warndialog anzeigen
--scale      	  Schieberegler-Dialog anzeigen

Calendar

Der calendar Dialog gibt einen schönen Monatskalender aus, von dem ein Datum ausgewählt werden kann. Sie können Text und einen Titel angeben, die zusammen mit Tag, Monat und Jahr ausgegeben werden, wenn der Dialog aufgerufen wird. Ebenso können Höhe und Breite des Dialogfensters festgelegt werden. Weil der Befehl recht lang werden kann, habe ich das Zeilenverlängerungszeichen \ eingesetzt, um Platz zu sparen. Die Shell betrachtet aber alles als eine Zeile.

zenity --calendar --title="Janes Calendar" \
--text="pick a date" \
--day=15 \
--month=6 \
--year=2020 \
--width=300
pic

Das ausgewählte Datum wird standardmäßig im Format 06/15/2020 zurückgegeben, aber es gibt eine weitere Option, um jederzeit Ihre Ausgabe im Griff zu haben.

--date-option=STRING

Dabei stimmt STRING mit der Spezifikation der strftime Funktion überein. Hier kann man noch viel mehr machen (Google ist Ihr Freund), aber in Kürze:

"%A %d/%m/%Y" erzeugt Monday 15/06/2020 und
"%a %d %B %Y" ändert dies zu Mon 15 June 2020.
Haben Sie es verstanden?

Das zurückgegebene Datum kann einfach in einer Variablen abgelegt werden, indem man den gesamten Befehl in Backticks setzt:

MYDATE=`zenity --calendar`

Wenn man die cancel Schaltfläche anklickt, wird ein leerer String zurückgegeben.

Text Entry

Der text entry Dialog stellt eine einfache Möglichkeit bereit, Daten in ein Script einzulesen. Die Option --entry-text erlaubt die Darstellung des Standardtextes, wenn der Dialog angezeigt wird.

zenity --entry --text="Please enter your name" --entry-text="name"
pic

Eine nützliche Eigenschaft ist die --hide-text Option. Damit können Passwörter eingegeben werden.

pic

Achten Sie jedoch darauf, dass nicht eine unverschlüsselte Zeichenkette zurückgegeben wird.

Error, Warning, Question and Information

Diese vier sehr einfachen Dialogboxen werden nachstehend mit ihren Standardicons und Standardtext abgebildet.

Selbstverständlich können Text, Breite und Höhe mit den entsprechenden --text, --width und --height Optionen den Anforderungen der Anwendung entsprechend angepasst werden.

pic
pic
pic
pic

File Selection

Durch den Dialog file selection können wir auf elegante Weise über ein Interface aus Dateien lesen oder in Dateien schreiben. Dabei wird nicht wirklich eine Lese – oder Schreibfunktion ausgeführt, dies muss durch das Script ausgeführt werden, aber es vereinfacht die Angelegenheit für beide, den Benutzer und den Script Verfasser.

Der Standardmodus des Dialogs ist der Lesemodus, er gibt den Namen der gewählten Datei, zusammen mit dem vollständigen Pfad zurück. Wenn die Option --multiple angegeben ist, können mehrere Dateien ausgewählt werden. Sie werden getrennt durch einen vertikalen Strich | zurückgegeben. Dieses Trennungszeichen kann über die Option --separator=SEPARATOR_CHRACTER verändert werden. Die --directory Option beschränkt die Auswahl ausschließlich auf Verzeichnisse. Die --save Option fügt eine Texteingabemöglichkeit hinzu, die nach einem Dateinamen fragt, der mit der --filename=FILENAME Option voreingestellt werden kann. Dies erlaubt mittels eines grafischen Verfahrens die Auswahl von Namen und Verzeichnis, unter denen die Datei gespeichert werden soll. Dateinamen und Pfad werden vom Befehl zurückgegeben. Bei gesetzter --confirm-overwrite Option wird ein Warndialogfenster angezeigt, wenn die Datei bereits vorhanden ist.

Der Befehl

zenity --file-selection --save --confirm-overwrite 

führt zur folgenden Dialogbox.

pic

Gibt man den Namen einer bereits vorhandenen Datei ein, wird der Benutzer gewarnt.

pic

Klickt man auf "Browse for other folders", oder öffnet man den Dialog im Standardlesemodus (ohne Angabe der --save Option), dann öffnet sich ein vollständiger Dateisuchdialog, mit dem die meisten GUI Nutzer wohl zufrieden sind.

pic

Benachrichtigung (notification)

Die Option --notification legt im Systembereich der Kontrollleiste ein kleines Icon ab. Wenn der Mauszeiger über die Iconfläche fährt, wird ein Text bezüglich des Werkzeugs angezeigt. Dieser "tooltip" wird über die --text=TEXT Option festgelegt.

pic

Der Befehl kennt noch eine weitere Option, --listen, die Dateneingabe über stdin erwartet. Diese Option zu nutzen ist ein bisschen schwieriger, da stdin gewöhnlich den Dateidescriptor 0 verwendet. Aber indem wir echo benutzen, können wir Daten mit einem anderen Dateidescriptor verschicken. Die listen Option erwartet einen von drei Optionsbefehlen – tooltip, icon und visible. Dies erlaubt uns dynamisch den angezeigten Text, das Icon im Systemtray und die Darstellung des Icons zu beeinflussen. Eine nützliche Sache, wenn man feedback vom Script zum Benutzer übertragen will.

zenity --notification --text="PCLinuxOS"

legt ein dreieckiges Warnicon im Systemtray ab (s. oben) und gibt den tooltip "PCLinuxOS" aus.

Wollen wir die --listen Option nutzen, können wir Folgendes schreiben:

exec 3> >(zenity --notification --text="PCLinuxOS" --listen)

Dies sendet, unter Benutzung des Filedescriptors 3, alle Daten an den zenity Befehl. Filedescriptor 3 wurde verwendet, da 0, 1 und 2 bereits von stdin, stdout und stderr verwendet werden. Das gleiche Ergebnis wäre aber auch mit 7 oder sogar 27 erzielt worden.

Um das Icon ins "info-icon" zu verändern, können wir diese Information über Filedescriptor 3 mit echo ausgeben:

echo "icon: info" >&3

Dadurch wird das Icon so

pic

verändern

Um den tooltip zu ändern, geben wir

echo "tooltip: Radically Simple" >&3

ein und können auf diese Weise dem Befehl neue Informationen übergeben.

Um den notification Befehl zu beenden müssen wir nur den Filedescriptor schließen:

exec 3>&-

Text Information

Der Dialog text information erlaubt es, Text aus einer Datei an den Benutzer auszugeben. Der Text kann dem Befehl auch über eine pipe von einem anderen Befehl weitergereicht werden.

zenity --text-info --filename=Dateiname
pic

Mit der --editable Option lässt sich der dargestellte Text editieren. Der editierte Text wird dem Befehl als Text zurückgegeben, muss aber zwischengespeichert werden, da er nicht in die Quelldatei zurückgeschrieben wird.

Scale

Der scale Dialog stellt eine Balkenscala bereit, für die Schrittweite, maximal-, minimal- und Startwert festgesetzt werden können und auch, ob der jeweils aktuelle Wert angezeigt werden soll, oder nicht. Mit der Option --print-partial kann der aktuelle Wert über echo an das aufrufende Programm übergeben werden, wenn der Schiebeknopf bewegt wird. Beim Anklicken des OK Knopfs wird der Dialog geschlossen und der aktuelle Wert zurückgegeben. Der Schiebeknopf kann mit den Pfeiltasten oder mit der Maus bewegt werden. Im letzteren Fall wir der Wert für die Schrittweite ignoriert.

zenity --scale --min-value=0 --max-value=100 --value=76 --text="Set The Value"
pic

List

Für den list Dialog gibt es sehr viele Optionen. Sie können eine Anzahl benannter Spalten einrichten und Daten, die dort angezeigt werden sollen, in der entsprechenden Reihenfolge eingeben. Der Benutzer kann eine oder mehrere Reihen auswählen und durch Anklicken des OK Knopfes die ausgewählten Daten an das Script zurückgeben. Verwendet man die --checklist Option, so wird der ersten Spalte einer Reihe eine Checkbox angefügt, die es dem Benutzer erlaubt, diese Reihe auszuwählen. Alle angeklickten Checkboxes geben Daten an das Script zurück. Das erste Datenelement, das an jede Zeile geschickt wird, sollte entweder TRUE oder FALSE sein, um den Ausgangszustand der Box festzulegen. Die Option --radiolist stellt Radioknöpfe bereit, funktioniert aber sonst genauso.

Standardmäßig gibt der Befehl Daten aus der ersten Datenspalte zurück, aber dies kann mit Option --print-column geändert werden. Gibt man hier ALL ein, wird die ganze Spalte zurückgegeben. Daten, die zurückgegeben werden, sind durch das Vertikaltrennzeichen getrennt, aber auch das kann mit der Option --separator geändert werden. Mit der Option --editable kann der Benutzer die Daten editieren, bevor sie mit einem Klick auf den OK Knopf an das Script zurückgegeben werden.

Hier wäre vielleicht ein Beispiel nützlich.

zenity --list --column="Select" \
--column="Name" --column="e-mail" \
FALSE "John" "john.doe@home" \
TRUE "Dan" "dan.dare@space.com" \
FALSE "Bill" "billybob@microsoft.com" \
FALSE "Charles" "dickens@pickwick.uk" \
--print-column=ALL \
--separator=" "\
--checklist \
--height=240 \
--width=350
pic

Progress

Ein sehr gutes Beispiel für den progress Dialog liefert der Synaptic Package Manager. Auf den ersten Blick scheinen die anwählbaren Optionen nicht sehr viel Auswahl bereitzustellen, aber dieser kleine Dialog kann doch recht beeindruckend sein.

Das sind die Optionen:

--text=STRING     Set the dialog text
--percentage=INT  Set initial percentage
--auto-close      Close dialog when 100% has been reached
--auto-kill       Kill parent process if cancel button is pressed
--pulsate         Pulsate progress bar

Natürlich sind auch die allgemeinen Optionen wie Breite und Höhe verfügbar. Die Daten werden dem Befehl wahrscheinlich am Einfachsten über eine Pipe von einem vorausgehenden Befehl übergeben, aber sie können auch, wie im vorhergehenden Beispiel, über einen Dateidescriptor eingelesen werden.

pic
pic

Das gibt mit echo den Text an den Befehl zurück und aktualisiert den Fortschrittsbalken, wenn neue Daten gesendet werden. Text, dem ein # voransteht, aktualisiert die --title Option und die Zahlen aktualisieren die --progress Option. Der Befehl sleep n bewirkt, dass während n Sekunden nichts passiert und Sie so sehen können, was vor sich geht, aber normalerweise würden Sie an dieser Stelle etwas Sinnvolles ausführen. Eine weitere Option ist --pulsate. Damit bewegt sich der Fortschrittsbalken vor oder zurück, bis der Befehl beendet ist, oder ein Zeichen für Dateiende erhalten wird. Die Option --auto-close schließt den Dialog automatisch und ohne Eingriffe des Benutzers, wenn der Prozess vollständig (zu 100%) abgelaufen ist.

Wenn Sie redirection benutzen, um einem Dialog Informationen über einen Befehl wie

ls /bin | (zenity –text-info)

zuzuführen, dann wird diese Information vom zenity Befehl absorbiert. Um dies zu umgehen, können wir den tee Befehl nutzen. tee vervielfältigt die Daten und gibt sie an verschiedene Pipes weiter.

ls /bin | tee >(zenity –text-info) >bin.txt

Dies trägt die Ausgabe des ls Befehls in den Dialog ein und sendet sie gleichzeitig an die Datei bin.txt.