Miniprogramme für die Shell schreiben

Aus EasyLinux 02/2016

Miniprogramme für die Shell schreiben

© Fotoclip Collection

Scripted Reality

Aus den Shell-Tipps und dem Guru-Training kennen Sie viele nützliche Kommandozeilentools. Die können Sie in kleinen Shell-Skripten zu leistungsfähigen Miniprogrammen bündeln. Im einfachsten Fall lassen Sie damit mehrere Befehle automatisch nacheinander ablaufen, doch Skripte haben noch mehr zu bieten.

Nützliche Shell-Skripte zu schreiben, erfordert in erste Linie ein wenig Kreativität – daneben müssen angehende Shell-Programmierer auch wissen, wie man solche Skripte grundsätzlich erstellt: Da geht es um den formalen Aufbau von Skriptdateien, die Syntax der Standard-Shell bash. Die ist aber schnell erlernt, und wenn Sie diese einmal beherrschen, sind Ihnen kaum Grenzen gesetzt.

Ausgangspunkt jedes (nützlichen) neuen Shell-Skripts ist immer der Wunsch, eine Aufgabe zu automatisieren. Leztztlich geht es darum, Zeit zu sparen und langweilige Wiederholungen zu meiden. Nehmen wir als Einstiegsbeispiel an, dass Sie sich regelmäßig auf der Shell über den freien Arbeitsspeicher und den freien Festplattenplatz auf der Partition, die /home/ enthält, informieren möchten. In der Shell würden Sie dazu die zwei Befehle free und df -h /home verwenden. Machen Sie genau das (warum auch immer) mehrmals am Tag, überlegen Sie sich mit der Zeit, dass hier ein Shell-Skript die Tipparbeit reduzieren könnte.

Alias für Kurzbefehle

Für diese noch sehr einfache Aufgabenstellung können Sie auch die Alias-Funktion nutzen, die in die Shell eingebaut ist: Geben Sie z. B.

alias i="free; df -h /home"

ein, können Sie anschließend einfach den Befehl i verwenden, um die beiden Kommandos nacheinander abarbeiten zu lassen. Das Semikolon trennt die beiden Befehle voneinander. Das funktioniert aber nur in der Shell, in der Sie dieses Alias gesetzt haben. Tragen Sie die Zeile am Ende der Datei ~/.bashrc ein, ist der neue Befehl auch in allen zukünftig geöffneten Shell-Fenstern verfügbar.

Hier soll es aber um Skripte gehen, also basteln Sie statt des Alias eine Skriptdatei. Dazu benötigen Sie einen Texteditor, z. B. Kate oder gedit; wenn Sie den Konsoleneditor vi kennen (und bedienen können), geht es damit schneller und ohne Zusatzfenster. In eine neue, leere Datei tragen Sie die Zeile

free; df -h /home

ein und speichern – schon haben Sie die erste Skriptdatei erstellt. Diese müssen Sie noch ausführbar machen, z. B. über das Kommando

chmod a+x Dateiname

Liegt die Datei im aktuellen Arbeitsverzeichnis und heißt z. B. i.sh, können Sie diese anschließend mit

./i.sh

ausführen – der führende Punkt ist wichtig, damit die Shell die Skriptdatei findet, weil sie (zumindest standardmäßig) nicht im aktuellen Ordner sucht, sondern eine über die Shell-Variable PATH festgelegte Liste von Ordnern nach ausführbaren Programmen durchsucht. Wie im Beispiel, ist es üblich, Shell-Skripten die Dateiendung .sh zu geben – nötig ist das aber nicht, Sie können auch ganz ohne Endung arbeiten und die Datei z. B. nur i nennen.

In Shell-Skripten verzichtet man (u. a. wegen einer besseren Lesbarkeit) meist darauf, mehrere Befehle in eine Zeile zu schreiben. Außerdem ist es sinnvoll, in der ersten Zeile der Skriptdatei anzugeben, welche Shell das Skript ausführen soll. Schließlich bietet es sich an, Befehle zu kommentieren: Bei kleineren Skripten ist das überflüssig, aber komplexere Skriptdateien bleiben damit auch Jahre später noch verständlich. Einen Kommentar ergänzen Sie in einer Zeile hinter der Raute (#). Die so veränderte Version der Datei hat diesen Aufbau:

#!/bin/bash
free           # Arbeitsspeicher
df -h /home    # Plattenplatz

Die erste Zeile enthält einen speziellen Kommentar; hinter #! (mit zusätzlichem Ausrufezeichen) steht der Pfad zur Shell (Bash), und damit sagen Sie dem System, dass die Bash – und nicht etwa eine andere Shell – das Skript ausführen soll. Diese Zeile sollten Sie an den Anfang jeder Skriptdatei stellen.

Ändern Sie nachträglich eine schon mit chmod ausführbar gemachte Skriptdatei, bleibt die Eigenschaft erhalten; es ist also nicht nötig, erneut ein chmod-Kommando einzugeben.

Pipelines

Schon aus dem normalen Shell-Einsatz kennen Sie vielleicht die mit dem Zeichen “|” erzeugten Pipes. Ein kleines Beispiel für dessen Einsatz ist die Such nach dem größten Unterordner im aktuellen Verzeichnis: Mit

du -sm *

lassen Sie sich für jede Datei und jeden Ordner im aktuellen Arbeitsverzeichnis den belegten Speicher in MByte ausgeben. Das erzeugt eine Ausgabe wie in Listing 1.

Listing 1

Unsortierte “du”-Ausgabe

$ du -sm *
0       00_anzeigen
5       01_layout
1       02_layoutueberpruefung
1       03_schlussredaktion
1       04_layoutendcheck
1       05_pdf-endcheck
0       06_final
18      07_dvd-labels
210     0_vorlagen
1       10_seitenplan
0       11_online
151     html
276     orig_txt

Die Ausgabe ist informativ, leidet aber bei einer längeren Liste daran, dass sie unsortiert ist. Sie könnten die Programmausgabe in eine Ausgabedatei umleiten, indem Sie an den Befehl > datei anhängen und die so erzeugte Datei dann mit sort -n datei numerisch (-n) sortiert ausgeben – einfacher geht es mit einer Pipe. Dazu kombinieren Sie die beiden Kommandos, schreiben also

du -sm * | sort -n

Die Pipe erspart Ihnen somit die Verwendung einer temporären Datei für Zwischenergebnisse. Listing 2 zeigt den Effekt im direkten Vergleich: Die größten Ergebnisse stehen jetzt am Ende der Ausgabe. Auch solche Pipes können Sie in ein Shell-Skript einbauen.

Listing 2

Sortierte “du”-Ausgabe

$ du -sm * | sort -n
0       00_anzeigen
0       06_final
0       11_online
1       02_layoutueberpruefung
1       03_schlussredaktion
1       04_layoutendcheck
1       05_pdf-endcheck
1       10_seitenplan
5       01_layout
18      07_dvd-labels
151     html
210     0_vorlagen
276     orig_txt

Pipes können zudem aus mehr als zwei Kommandos bestehen, Ihrem Erfindungsreichtum sind also keine Grenzen gesetzt.

Komplexere Skripte

Ein längeres Beispielskript, das aber immer noch lediglich mehrere Befehle nacheinander ausführt, sehen Sie in Listing 3: Rufen Sie es nach dem Anstöpseln einer Digitalkamera (oder dem Einstecken einer Speicherkarte) auf, erzeugt es automatisch einen neuen Unterordner mit einem Namen der Form 2016-04-30 und verschiebt alle Bilder von der Karte in diesen Ordner. Mit Smartphones funktioniert das übrigens in der Regel nicht, weil sich viele aktuelle Geräte beim Anschließen über USB nicht mehr als Datenträger, sondern als PTP– oder MTP-Gerät anmelden (Abbildung 1). Wie Sie mit ein paar Änderungen trotzdem auf die Smartphone-Fotos zugreifen können, verrät der Kasten Zugriff aufs Smartphone.

Abbildung 1: Viele Smartphones erlauben keinen direkten Zugriff auf das Dateisystem, so z. B. das Samsung Galaxy S5, das die Wahl zwischen MTP- und PTP-Verbindungen lässt.

Abbildung 1: Viele Smartphones erlauben keinen direkten Zugriff auf das Dateisystem, so z. B. das Samsung Galaxy S5, das die Wahl zwischen MTP- und PTP-Verbindungen lässt.

Listing 3

Bilder kopieren

#!/bin/bash
CAMERA=/media/camera/DCIM/100XYZAB
ZIEL=$HOME/Pictures/Import
DATE=$( date +%Y-%m-%d )
mkdir $ZIEL/$DATE
mv -v $CAMERA/* $ZIEL/$DATE/
sync
echo Bilder kopiert.

Schauen wir uns das Listing Zeile für Zeile an:

#!/bin/bash

In der ersten Zeile steht wieder der Hinweis, dass die Shell /bin/bash das Skript ausführen soll.

CAMERA=/media/camera/DCIM/100XYZAB

Die folgende Zeile definiert eine Variable CAMERA und weist ihr den Wert /media/camera/DCIM zu. Wenn Sie das Skript mit Ihrer eigenen Kamera oder dem Smartphone ausprobieren möchten, müssen Sie diesen Pfad anpassen. Nach dem Anschließen der Kamera wird diese eingebunden. Unterhalb von /media/ oder in einem Ordner in Ihrem Home-Verzeichnis finden Sie dann einen neuen Ordner, der meist eine Kurzbezeichnung Ihres Kameramodells oder der Herstellers als Namen trägt. (Geben Sie den Befehl mount ein, um eine Liste aller eingehängten Datenträger zu sehen.)

Auf der obersten Ebene des Kameradateisystems gibt es einen Ordner DCIM/, der ein weiteres Unterverzeichnis enthält – im Beispiel 100XYZAB; bei Ihnen wird es anders heißen. Setzen Sie den korrekten Pfad in der obigen Zeile ein, wenn Sie das Skript testen möchten.

ZIEL=$HOME/Pictures/Import

Ähnlich wie CAMERA den Ort speichert, in dem die Bilder auf der Kamera liegen, ist auch ZIEL eine Variable, in die Sie das Verzeichnis eintragen, in welches das Skript die Bilder kopieren soll. In diesem Beispiel gehen wir davon aus, dass es in Ihrem Home-Verzeichnis (das sich über $HOME ansprechen lässt) einen Ordner Pictures gibt – und darin einen Unterordner Import. Falls das nicht der Fall ist, ist es auch nicht tragisch, denn der übernächste Befehl wird diese Verzeichnisse erzeugen.

DATE=$( date +%Y-%m-%d )

Dieses Kommando ist komplexer. Schauen wir zunächst in die Klammern: Dort steht das Kommando date +%Y-%m-%d. Ohne Argumente gibt date das aktuelle Datum und die Uhrzeit aus. Mit den Angaben hinter dem Pluszeichen definieren Sie ein Format – %Y-%m-%d sorgt dafür, dass die Ausgabe im Format 2016-04-30 erfolgt. Würden Sie also in der Shell direkt date +%Y-%m-%d eingeben, würde das Tool das aktuelle Datum im Format 2016-04-30 ausgeben. Die Konstruktion $( ... ) nimmt nun die Ausgabe dieses Befehls und macht daraus ein Argument. Am Anfang steht ja noch der Zuweisungsbefehl DATE=. Das gesamte Kommando schreibt also in die Variable DATE das aktuelle Datum.

mkdir -p $ZIEL/$DATE

Jetzt wird ein neuer Ordner erstellt – der Pfad setzt sich aus $ZIEL, dem Verzeichnistrenner / und $DATE zusammen. Beachten Sie hier, dass Sie beim Setzen einer Variable den Namen ohne Dollarzeichen benutzen, beim Zugriff auf den Inhalt hingegen ein Dollarzeichen voranstellen müssen. Wenn $HOME z. B. den Wert /home/user hat, ergibt sich über die Definitionen von ZIEL und DATE ein Befehl der Form mkdir -p /home/user/Pictures/Import/2016-04-30. Die Option -p für das mkdir-Kommando sorgt dafür, dass eventuell fehlende Verzeichnisse “auf dem Weg” (also .../Pictures/Import und .../Pictures) gleich mit erzeugt werden, so dass dieses Kommando nicht fehlschlagen kann.

mv -v $CAMERA/* $ZIEL/$DATE/

Das vorvorletzte Kommando verschiebt dann alle Dateien im Bilderordner der Kamera in den Bilderordner auf Ihrer Festplatte; die Option -v sorgt dafür, dass mv die Namen aller verschobenen Dateien auf der Konsole ausgibt, damit Sie den Fortschritt verfolgen können.

sync

Mit sync sorgen Sie schließlich dafür, dass Sie nach Ausführen des Skripts die Kamera einfach abstöpseln können, ohne Datenverlust zu riskieren.

echo Bilder kopiert.

Zum Schluss gibt es noch eine Statusmeldung. Damit Sie das Skript verwenden können, speichern Sie es (z. B. als copycam.sh in Ihrem Home-Verzeichnis) und machen es mit

chmod a+x copycam.sh

ausführbar. Dann können Sie es später mit

~/copycam.sh

aufrufen. Wenn Sie die Datei (mit Root-Rechten) in das Verzeichnis /usr/local/bin/ kopieren, können Sie die Pfadangabe auch weglassen, also in der Shell einfach copycam.sh eingeben.

Bearbeiten Sie ein Shell-Skript im Editor, kommen Sie übrigens in der Regel in den Genuss von Syntax Highlighting, der Editor hebt Schlüsselwörter, Klammern und Variablennamen farbig hervor. Das funktioniert z. B. in KDEs Editor Kate (Abbildung 2) und im Konsolen-Editor vi.

Abbildung 2: KDEs Editor Kate erkennt Shell-Skripte und aktiviert beim Bearbeiten das Syntax Highlighting.

Abbildung 2: KDEs Editor Kate erkennt Shell-Skripte und aktiviert beim Bearbeiten das Syntax Highlighting.

Zugriff aufs Smartphone

Wenn Sie klassisch (also über das Einhängen ins Dateisystem) auf die Smartphone-Fotos zugreifen möchten, können Sie dazu eines der Programmpakete gphotofs (für PTP) oder mtpfs (für MTP) nachinstallieren. Unter Kubuntu gelingt das mit

sudo apt-get install Paketname

Bei OpenSuse sind die nötigen Repositorys für die Pakete noch nicht eingetragen, darum ist die One-Click-Installation über die Paketsuche am leichtesten [4, 5].

Sind die Tools einmal installiert, legen Sie nur einen Mountpoint (einen leeren Ordner, z. B. mtp/ direkt in Ihrem Home-Verzeichnis) an und geben dann das Kommando mtpfs mtp bzw. gphotofs mtp ein. Das Programm kümmert sich dann um den Verbindungsaufbau, und im Anschluss haben Sie über den gewählten Ordner Zugriff auf die via PTP und MTP bereitgestellten Dateien (Abbildung 3).

Abbildung 3: Beim Testgerät (Galaxy S5) gelang nur der PTP-Zugriff.

Abbildung 3: Beim Testgerät (Galaxy S5) gelang nur der PTP-Zugriff.

Die Ordnerstruktur, die via PTP/MTP sichtbar wird, ist komplexer als bei einfachen Digitalkameras. Der Mountpoint enthält meist zwei Unterordner, einen für den fest verbauten Speicher und einen für die eingesetzte SD-Karte. Abhängig von den Einstellungen der Foto-App finden Sie dann in einem dieser Ordner das Verzeichnis DCIM, welches in einem weiteren Unterordner dann endlich Zugriff auf die Fotos gewährt. Auf unserem Testgerät haben wir die Bilder in store_00020002/DCIM/Camera/ gefunden.

Um den Zugriff zu beenden, verwenden Sie das Kommando fusermount -u mtp/ (wobei Sie mtp/ durch den von Ihnen beim Aufruf von gphotofs oder mtpfs gewählten Mountpoint ersetzen).

Bash als Programmiersprache

Richtige Programmiersprachen können aber mehr, als nur einfache Befehlssequenzen abzuarbeiten. So helfen Fallunterscheidungen (so genannte If-Then-Else-Konstruktionen), Schleifen (mit dem Spezialfall der Zählschleife) sowie Prozeduren bzw. Funktionen, den Ablauf variabler zu gestalten.

Fallunterscheidungen haben in der Shell die folgende Syntax:

if Bedingung
then Befehle
else Befehle
fi

Die Befehlsworte sind also if, then, else und fi (eine rückwärts geschriebene Form von if, die das Ende der Fallunterscheidung anzeigt). Der Else-Fall muss nicht vorhanden sein. Die Idee ist dabei, dass die Shell eine Bedingung prüft und abhängig vom Ergebnis (das wahr oder falsch sein kann) den einen oder anderen Zweig der If-Then-Else-Konstruktion abarbeitet. Das folgende Beispielskript exist prüft, ob eine Datei existiert:

#!/bin/bash
if test "$1" = ""
then echo "$0: mit Dateinamen aufrufen!"; exit
fi
if test -e $1
then echo $1 existiert
else echo $1 existiert nicht
fi

Der erste Test prüft mit dem in die Shell eingebauten Kommando test, ob das Skript überhaupt mit einem Argument aufgerufen wurde ($1 ist das erste Argument; wenn es das nicht gibt, ist $1 ein leerer String). Ist kein Argument vorhanden, bricht das Programm mit exit ab. Das funktioniert, weil das Skript in einer “Sub-Shell”, also einem eigenen Shell-Prozess läuft.

Zum “Then-Fall” gehören also zwei Kommandos, die hier mit einem Semikolon voneinander getrennt sind – Sie können sie alternativ auch in mehrere Zeilen des Programms schreiben. Oft stehen auch then und else alleine in jeweils einer Zeile, und die Kommandos für die beiden Fälle folgen darunter. Eine üblichere (wenn auch weniger kompakte Schreibweise) der ersten Fallunterscheidung ist damit die folgende:

if test "$1" = ""
then
  echo "$0: mit Dateinamen aufrufen!"
  exit
fi

Ein direkter Vergleich mit if "$1" = "" ist übrigens nicht möglich: Die Bedingung in einer Fallunterscheidung muss immer ein Kommando sein, dessen Rückgabewert die Shell dann prüft. Zum Beispiel gibt es die beiden Programme true und false, die beide keine sichtbare Funktion haben, aber die Rückgabewerte 0 und 1 produzieren – den Rückgabewert des jeweils letzten Befehls lesen Sie über $? aus:

$ true; echo $?
0
$ false; echo $?
1
$ if true; then echo Ja; else echo Nein; fi
Ja

Zurück zum exist-Skript: Der zweite Test ruft test -e $1 auf. Wenn Sie in die Dokumentation zu test schauen (das geht mit help test, weil test ein Shell-Builtin, also ein fest in die Shell eingebautes Kommando ist), sehen Sie, dass das Kommando über -e dateiname prüft, ob eine bestimmte Datei vorhanden ist.

Um eine Syntax zu erlauben, die stärker an normale Programmiersprachen erinnert, können Sie statt des Schlüsselworts test auch öffnende und schließende eckige Klammern verwenden, z. B.

if [ "$1" = "" ]

Beachten Sie dabei, dass die Klammern zu den übrigen Komponenten der Zeile mit einem Leerzeichen Abstand halten müssen; der Ausdruck

if ["$1" = ""]

enthält also zwei Syntaxfehler. Für andere Shells als die Bash gibt es sogar ein Programm /bin/[, welches genauso arbeitet. Sie könnten darum auch den merkwürdigen Ausdruck

if /bin/[ "$1" = "" ]

verwenden, wenn Sie die Leser Ihrer Skripte irritieren möchten. Kombinieren Sie die Klammerschreibweise und das Aufteilen auf mehrere Zeilen, entsteht hübscher Code, der intuitiv zu verstehen ist:

if [ "$1" = "" ]
then
  echo "$0: mit Dateinamen aufrufen!"
  exit
fi

(Haben Sie $0 bemerkt? Darüber können Sie den Namen der Skript-Datei herausfinden.) Wollen Sie mehr als zwei Fälle prüfen, können Sie ein weiteres Schlüsselwort verwenden: elif steht für “else if”, ein Beispiel:

if [ "$1" = "a" ]
then echo "a"
elif [ "$1" = "b" ]
then echo "b"
elif [ "$1" = "c" ]
then echo "c"
else echo "Weder a noch b noch c"
fi

Case-Befehl

Für mehrere Tests, die alle den Inhalt derselben Variable prüfen, können Sie auch den case-Befehl nutzen, der diese Aktionen übersichtlicher macht:

case "$1" in
  "a")
    echo "a" ;;
  "b")
    echo "b" ;;
  *)
    echo "Weder a noch b" ;;
esac

Hinter jedem Fall steht eine schließende Klammer; dann folgen einer oder mehrere Befehle, und der Code für einen Fall muss mit doppelten Semikola (;;) enden. Der gesamte case-Ausdruck endet mit esac, was wieder (wie bei iffi eine Rückwärtsschreibung von case ist.

For-Schleife

Die Bash kennt keine klassische Zählschleife, die eine Variable von einem Anfangs- zu einem Endwert hochzählt. Stattdessen gibt es etwas, das in anderen Sprachen als For-Each-Schleife bezeichnet wird. So können Sie z. B. schreiben:

for entry in *
do
  if [ ! -e $entry ]
  then echo "$entry gibt es nicht"
    continue
  fi
  if [ -f $entry ]
  then echo "Datei $entry"
  fi
  if [ -d $entry ]
  then echo "Verzeichnis $entry"
  fi
done

Das Sternchen ist das normale Wildcard-Zeichen; in der Schleife nimmt die Variable $entry nacheinander alle Namen von Dateien und Verzeichnissen im aktuellen Ordner an.

Die For-Schleife beenden Sie mit done. Neu in diesem Beispiel ist auch das Ausrufezeichen: Es kehrt den Wahrheitswert eines Tests um. Einen Test auf Ungleichheit zweier Variablen können Sie also z. B. als [ ! "$x" = "$y" ] schreiben – allerdings gibt es dafür auch die lesbarere Form [ "$x" != "$y" ].

Ein Klassiker der Bash-Skripte (auch hier in EasyLinux) ist das Konvertieren von Bildern, etwa in zusätzliche Vorschaubilder. Wollen Sie z. B. eine Fotogalerie erstellen, werden Sie meist auch kleine Versionen der Bilder benötigen. Sie können dazu einfach einen Vierzeiler (minipics.sh) schreiben:

#!/bin/bash
for Bild in *.jpg; do
  Mininame=$( basename $Bild .jpg )_s.jpg
  echo Erzeuge Vorschaubild für $Bild
  convert "$Bild" -resize 100x100 "$Mininame"
done

In der Schleife erhält die Variable Bild nacheinander die Namen aller JPG-Dateien (mit Endung .jpg und führt für jede dieser Dateien die Befehle im Inneren der Schleife aus: Zunächst wird der Name für die Vorschaudatei bestimmt: Hier nutzt das Skript die $(...)$-Konstruktion, die Sie bereits im ersten Skript gesehen haben. Innerhalb der Klammern entfernt der Befehl basename $Bild .jpg vom Ursprungsdateinamen die Endung (aus foto1.jpg wird also foto1), an das Ergebnis wird _s.jpg angehängt (so dass im Beispiel foto1_s.jpg entsteht. Diesen Namen speichert der Befehl in der Variablen Mininame.

Schließlich erledigt das Tool convert (aus dem ImageMagick-Paket, das Sie eventuell nachinstallieren müssen) die Umwandlung. Es verwendet die Variablen Bild und Mininame, in denen die Namen der Quell- und Zieldateien stehen, und sorgt über die Option -resize 100x100 dafür, dass die neue Datei Abmessungen hat, die 100 x 100 Pixel nicht überschreiten; die Seitenverhältnisse bleiben dabei erhalten: Ein Bild der Größe 600 x 400 Pixel wird darum auf 100 x 67 Pixel verkleinert. Abbildung 4 zeigt, wie das Skript arbeitet.

Abbildung 4: Das Skript "minipics.sh" erzeugt maximal 100 x 100 Pixel große Vorschaubilder.

Abbildung 4: Das Skript “minipics.sh” erzeugt maximal 100 x 100 Pixel große Vorschaubilder.

Zählschleife

Über einen kleinen Trick können Sie auch eine Zählschleife programmieren. Zwar gibt es keine spezielle Syntax für das Hochzählen, aber dafür können Sie das Programm seq verwenden, das eine Sequenz aus Zahlen generiert:

$ seq 5 8
5
6
7
8

Über die schon zweimal gesehene $(...)-Konstruktion können Sie diese Zahlenwerte in einen anderen Befehl integrieren. Um in einer Variablen $i von 1 bis 100 zu zählen, schreiben Sie:

for i in $(seq 1 100)
do
  ...
done

Das Programm seq können Sie auch mit drei Argumenten aufrufen, das mittlere steht dann für die Veränderung, die in jedem Schritt stattfindet – normal wird immer 1 addiert. Dieser mittlere Wert darf auch negativ sein, was aber voraussetzt, dass der Anfangswert größer als der Endwert ist:

$ echo $( seq 20 -3 0 )
20 17 14 11 8 5 2

Wie Sie an diesem Beispiel sehen, wird der Endwert eventuell nicht erreicht; nach 2 wäre der nächste Wert -1, der ist aber zu klein, darum taucht er nicht mehr in der Ausgabe auf.

While-Schleife

Als letzte Schleife erwähnen wir die While-Schleife, sie hat die Syntax

while Bedingung
doBefehle
done

und führt die Befehle im Inneren aus, solange die Bedingung erfüllt ist – sie prüft dabei immer am Anfang. Sie können leicht ein interaktives Skript erstellen, das Eingaben von der Tastatur liest und abbricht, wenn Sie z. B. exit eingeben:

read x
while [ "$x" != "exit" ]
do
  echo Eingabe war $x
  read x
done

Es verwendet das Kommando read, das einen oder mehrere Variablennamen als Argumente akzeptiert. Geben Sie (wie oben) nur einen Namen an, landet die ganze eingegebene Zeile in der Variable. Wenn Sie mehrere Variablen angeben, zerlegt read Ihre Eingabe in Teile und weist diese den Variablen zu. (Trennzeichen sind das Leer- und das Tabulatorzeichen.) Wenn es in diesem Fall mehr Teile als Variablen gibt, landet der Rest in der letzten Variable.

Funktionen

Zum Abschluss stellen wir noch Shell-interne Funktionen vor: Diese können Sie einfach in einer C-ähnlichen Syntax definieren und dann direkt in der Shell oder in einem Skript verwenden.

Anders als in normalen Programmiersprachen erhalten Funktionsargumente keine Namen, sondern werden über ihre Aufrufposition angesprochen; das funktioniert wie beim Aufruf eines Shell-Skripts:

function addiere {
  echo Berechne $1 plus $2
  ergebnis=$(( $1 + $2 ))
  echo Summe ist $ergebnis
}

Die Funktion können Sie mit zwei Argumenten aufrufen, z. B. addiere 5 20, und Sie erhalten dann die Ausgabe

Berechne 5 plus 20
Summe ist 25

Bei der Gelegenheit haben Sie auch gleich gesehen, wie Sie in der Shell rechnen können; Sie packen dazu den mathematischen Ausdruck einfach in $((...)). Es gibt hier nur Integer-Werte, Sie können also keine Zahlen mit Nachkommastellen verwenden. Auch bei der Berechnung von Brüchen (mit /) entstehen immer ganze Werte, die Shell führt eine Division mit Rest durch:

$ echo $(( 5/3 )), $(( 6/3 ))
1, 2

Hilfe im Netz

Um das Rad nicht mehrfach neu zu erfinden, können Sie im Internet auf Suche nach Skripten für bestimmte Aufgaben gehen: Viele Anwender veröffentlichen ihre Skript-Lösungen, und es fördert das Verständnis, wenn Sie ein solches Skript herunterladen und nachvollziehen, was es tut. Eine Sammlung von Skripten und Links zu anderen Webseiten über Skripte finden Sie auf der Shelldorado-Seite [1] (Abbildung 5).

Abbildung 5: Die Webseite "shelldorado.com" bietet unter anderem eine umfassende Linksammlung zu Shell-Skripten.

Abbildung 5: Die Webseite “shelldorado.com” bietet unter anderem eine umfassende Linksammlung zu Shell-Skripten.

Darüber hinaus hat der Rheinwerk-Verlag eine vollständige HTML-Version des Buchs “Shell-Programmierung” von Jürgen Wolf ins Netz gestellt [2], die gedruckte Version hat 780 Seiten, so dass ausreichend Lektüre für Ihre Ausbildung zum Shell-Programmierer vorhanden ist.

Wenn Sie bei eigenen Recherchen auf fremde Shell-Skripte stoßen und darin einzelne Befehle nicht verstehen, hilft die Webseite ExplainShell [3] weiter: Dort können Sie ein (kurzes oder auch komplexes) Kommando eingeben und erhalten dann eine ausführliche Erklärung zu Aufbau und Funktion (Abbildung 6).

Abbildung 6: Auf der Webseite "explainshell.com" lassen Sie Shell-Befehle analysieren und erklären.

Abbildung 6: Auf der Webseite “explainshell.com” lassen Sie Shell-Befehle analysieren und erklären.

Glossar

PTP

Das Picture Transfer Protocol ist ein älterer Standard für den Zugriff auf Digitalkameras, der ohne die Einbindung des Geräts als Datenträger arbeitet.

MTP

Das Media Transfer Protocol ist eine von Microsoft und Canon erdachte Weiterentwicklung von PTP, die z. B. auch den Transfer von MP3-Dateien auf entsprechende Player erlaubt.

Infos

[1] Heiners Shelldorado: http://www.shelldorado.com/

[2] Jürgen Wolf, “Shell-Programmierung. Einführung, Praxis, Referenz”, http://openbook.rheinwerk-verlag.de/shell_programmierung/

[3] ExplainShell: http://explainshell.com/

[4] gphotofs für OpenSuse: https://software.opensuse.org/package/gphotofs

[5] mtpfs für OpenSuse: https://software.opensuse.org/package/mtpfs

EasyLinux 02/2016 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