Bash-Programmierung
Aus PC-WELT-Wiki
|
Scripten mit Bash
Mit der Bash-Shell verfügen Linux-Systeme über ein mächtiges Werkzeug. Damit lassen sich viele Vorgänge automatisieren und Aufgaben lösen, für die es sonst kein passendes Programm gibt.
Unter Linux ist die Kommandozeile nach wie vor unverzichtbar. Beim Kompilieren und Installieren von Programmen, der Analyse und Wartung des Systems und der Nutzung zahlreicher einfacher Tools, macht der Anwender fast immer Bekanntschaft mit der Kommando-Shell Bash. Die Shell kann jedoch viel mehr, als nur einzelne Befehle direkt auf der Kommandzeile entgegennehmen und ausführen. Durch sinnvolle Verkettung mehrerer Kommandos hilft die Bash-Shell auch bei der Lösung komplexer Probleme. Zusammengefasst in einem Script und kombiniert mit externen Tools, lassen sich auch kleine Anwendungen erstellen, die Sie bei Routineaufgaben entlasten. Bei Bedarf ist es sogar möglich, die Scripte mit einer einfachen grafischen Oberfläche zu versehen, wahlweise für das Konsolenfenster oder KDE.
Viele Systemprozesse werden unter Linux ebenfalls über Bash-Scripte gestartet oder gesteuert. Manchmal sind hier Anpassungen notwendig. Daher ist es für Anwender, die etwas über die Interna des Systems erfahren wollen sinnvoll, mehr über die Grundlagen der Bash-Programmierung zu erfahren.
In diesem Artikel finden Sie zuerst einige Tipps zum effektiven Umgang mit der Bash-Shell und zum Ausführen von Programmen über die Kommandozeile. Danach zeigen wir Ihnen, wie Sie selbst einfache Scripte erstellen und mit einer Oberfläche ausstatten können. Die im Artikel genannten Beispiel-Scripte, können Sie unter dem Namen bashscripts.tar.gz über http://www.pcwelt-praxis.de herunterladen.
Neu Geboren: Vorteile der Bash-Shell
Unter Linux-System stehen Ihnen in fast immer mehrere, unterschiedliche Shells zur Verfügung. Die meisten sind allerdings nur noch von historischer Bedeutung und nur aus Gründen der Abwärtskompatibiltät mit dabei. Eine Shell lässt sich als um den Kernel herumliegende Schicht vorstellen, die dem Anwender die Interaktion mit dem System ermöglicht - daher auch der Name (englisch: shell für deutsch Hülle, Schale oder auch Muschel).
Der Standard ist heute bei praktisch allen Linux-Systemen die Bash-Shell. Der Name steht für Bourne Again Shell, da Bash kompatibel zur Bourne-Shell („sh“) ist. sh wurde etwa 1977 von Steve Bourne ursprünglich für Unix Version 7 entwickelt. Eine Vielzahl anderer, heute teilweise noch gebräuchlicher, Shells folgte nach, beispielsweise die C-Shell („csh“), die Korn-Shell („ksh“) oder die Turbo-C-Shell („tcsh“). Die Bash-Shell wurde erst 1988 von Brian Fox für das GNU-Projekt geschrieben und vereint daher alle Vorzüge ihrer Vorgänger, etwa leichtes Editieren auf der Kommandozeile, History-Liste, Job-Kontrolle oder Aliase zum vereinfachten Aufruf komplexerer Kommandos.
Viel Arbeit: Aufgabe einer Shell
Die Bash-Shell hat mehrere Funktionen. Im interaktiven Modus nimmt Sie vom Anwender Befehle entgegen, die sie in eine Binärsprache umsetzt, die der Kernel verstehen kann. Die Befehle kann die Shell jedoch nicht nur von der Tastatur, sondern auch aus einer Datei lesen. Dadurch ist die automatische Ausführung auch ohne Eingriff des Anwenders möglich. Die Shell muss in jedem Fall unterscheiden, ob es sich bei der Eingabe um ein externes Programm oder einen in der Bash-Shell eingebauten Befehl handelt. Ein Beispiel: „ls“, das Programm zum Auflisten des Verzeichnisinhalts liegt in /bin. Das Programm „cd", zuständig für den Verzeichniswechsel, werden Sie dagegen vergeblich auf der Festplatte suchen.
Die Shell startet jedoch nicht nur Programme und gibt die Rückgabewerte auf die Konsole aus, sie kann auch rechnen, Zeichenketten verarbeiten oder Kommandos in Abhängigkeit von bestimmten Ereignissen abarbeiten. Komplexere Kommandostrukturen gibt der Anwender dann allerdings nicht über die Tastatur ein, sondern legt sie in einer Textdatei ab. Die Shell arbeitet diese Zeile für Zeile ab und führt die darin enthaltenen Anweisungen oder Funktionen aus.
Interaktiv: Die Kommandozeile nutzen
Eine Kommandozeile in der Shell besteht aus einem oder mehreren Wörtern, die durch Leerzeichen oder TABs getrennt sind. Das erste Wort in einer Zeile ist das Kommando, die darauf folgenden sind Argumente (auch Parameter genannt), die das Kommando verarbeitet. Zusätzlich gibt es noch Optionen. Das sind besondere Arten von Argumenten, denen in der Regel ein Bindestrich („-“) vorangestellt ist. Die Übergabe der Befehlszeile an die Shell erfolgt Grundsätzlich erst nach Betätigung der <Return>-Taste.
Ein Beispiel: Der Befehl „ls“ zeigt die Dateien und Verzeichnisse im aktuellen Verzeichnis an. Mit der zusätzlichen Option „-l“ bewegen Sie „ls“ dazu, die Liste im Langformat auszugeben, also mit Datum und Größe. Die Eingabe von „ls -a -l“ erzeugt eine Liste mit allen Dateien im Langformat, einschließlich der Dateien, die mit einem Punkt beginnen. Beide Parameter erwarten keine zusätzlichen Argumente. Daher lassen Sie sich auch zu „ls -al“ zusammenziehen.
Die Ausgabe kann jedoch nicht nur auf den Bildschirm, sondern zur späteren Weiterverarbeitung auch in eine Datei erfolgen:
ls -al ~/Documents > Liste.txt
gibt beispielsweise die Datei- und Ordnerliste des Verzeichnisses „Documents“ im Homeverzeichnis in die Datei Liste.txt aus. Das Zeichen „>“ bewirkt nicht nur die Umleitung, sondern auch das Anlegen der Datei. Ist die Datei schon vorhanden, wird sie mit dem neuen Inhalt überschrieben. Wenn Sie stattdessen „>>“ verwenden, wird die Liste an eine bereits vorhandene Datei angehängt. Sollte die Datei beim ersten Aufruf noch nicht vorhanden sein, wird sie neu erstellt,
Ein andere Möglichkeit der Umleitung bietet das Pipe-Zeichen „|“. Die Zeile
ls -al | more
gibt die Datei-Liste an das Programm „more“ weiter. Dieses gibt immer nur so viele Zeilen aus, wie auf den Bildschirm passen. Mit dem Druck auf die Leertaste blättern Sie zur nächsten Seite. Die <Return>-Taste blättert zur nächsten Zeile.
Leichter Anfang: Das erste Script
Bei Bash-Scripten handelt es sich um einfache Textdateien. Sie erstellen sie daher mit einem Texteditor Ihrer Wahl, beispielsweise vi, emacs oder mcedit. Unter KDE ist der Editor Kate vorzuziehen. Er besitzt einige besondere Funktionen für das Bearbeiten von Shell-Scripts, etwa die farbige Hervorhebung von Schlüsselwörter (syntax highlighting) oder die strukturierte Darstellung von Funktionsblöcken (folding).
Ein Bash-Script fängt immer mit der Zeile
#!/bin/bash
an. Das Zeichen „#“ leitet eigentlich einen Kommentar ein, also eine Zeile, die die Shell ignorieren soll. In der Kombination „#!“ gibt sie jedoch die zu verwendende Shell an. Da nicht auf allen Systemen die Bash-Shell Standard sein muss, erfährt das System hier, welches Programm es starten soll. Das setzt natürlich voraus, das sich das /bin/bash tatsächlich existiert, was aber in der Regel der Fall sein dürfte.
Für einen ersten Test erstellen Sie mit Kate ein Datei mit folgendem Inhalt:
#!/bin/bash clear echo „Hello, World!“
Speichern Sie es in Ihrem Homeverzeichnis beispielsweise unter ~/Script/hello.sh. Öffnen Sie ein Konsolenfenster und geben Sie
chmod u+x ~/Script/hello.sh
ein. Damit setzen Sie das Datei-Attribut „Ausführbar“ für den Benutzer. Dieses müssen Sie bei jedem Script setzen, sonst lässt es sich nicht aufrufen.
Starten Sie das Script mit
cd ~/Script ./hello.sh
oder „~/Script/hello.sh“. Die Anweisung „clear“ in der zweiten Ziele löscht den Inhalt des Konsolenfensters. „echo“ gibt die nachfolgenden Zeichen bis zum Ende der Zeile auf den Bildschirm aus.
Tipp: Bei Scripten, die nicht im Suchpfad der Shell liegen, müssen Sie entweder den kompletten Pfad eintippen oder in das jeweilige Verzeichnis wechseln und „./“ voranstellen. Sie können sich die Arbeit erleichtern wenn Sie mit
export PATH=~/Script:$PATH
das Arbeitsverzeichnis vorübergehend in den Pfad aufnehmen
Werte speichern: Mit Variablen arbeiten
Scripte müssen sich beim Rechnen oder der bei Stringverarbeitung zur Laufzeit Werte merken können. Dazu dienen Variablen. Die Zuweisung erfolgt in der allgemeinen Form
VARIABLE=Wert
Es muss zwar nicht unbedingt sein, aber die meisten Programmierer benutzen, wegen der besseren Unterscheidbarkeit vom Programmcode, für Variablen ausschließlich Großbuchstaben. Ist der Wert zugewiesen, verwenden Sie die Variable danach mit einem vorangestellten "$", beispielsweise
VORNAME=Klaus echo "Mein Name ist $VORNAME"
Den Name für die Variablen können Sie fast beliebig wählen. Er darf aus Buchstaben und Zahlen bestehen. Eine Ausnahme sind reservierte Variablen: "$0" enthält immer den Namen des Scripts und "$1" bis "$<n>" die dem Script übergebenen Parameter. Umgebungsvariablen wie $PWD (aktueller Pfad) oder $USER (angemeldeter Benutzer) sind ebenfalls tabu.
Ein weitergehendes Beispiel für die Verwendung von Variablen, zeigt unser Script simplebackup.sh (-> Abbildung). Zu Beginn sind drei Variablen definiert: BACKUPDIR, SRCDIR und BACKUPFILE. BACKUPDIR erhält den Wert „~/backup“ und SRCDIR den Wert "~/Documents". Beide Verzeichnisse müssen existieren, damit das Script funktioniert. BACKUPFILE erhält seinen Wert dynaisch. Das Script konstruiert ihn aus der Zeichenfolge „doc.backup.“ und „$(date +%F).tgz“, Daraus ergibt sich ein Dateiname wie doc.backup.2005-07-26.tgz. Die Zeile
tar -cvzf $BACKUPDIR/$BACKUPFILE $SRCDIR
ruft schließlich das Programm „tar“ mit dem Variablen als Parameter auf. Damit erstellen Sie ein Sicherungskopie aller Dateien und Ordner unterhalb von ~/Documents im Backup-Verzeichnis. Wenn Sie das Script täglich einmal starten, erhalten Sie für jeden Tag eine eigene Sicherungskopie.
Wenn/Dann: Kontrollstrollstrukturen nutzen
Scripte sollen in vielen Fällen Anweisungen abhängig von Bedingungen ausführen. Das können bestimmte Eingaben des Benutzers oder Inhalte von Dateien sein. Der Code
if [ $1 -lt 10 ]; then echo "Die Eingabe war kleiner 10" else echo "Die Eingabe war größer oder gleich 10" fi
prüft beispielsweise mit „$1 -lt 10“, ob der eingegebene Wert kleine 10 ist. "$1" ist eine Variable (-> Punkt 5) und enthält als Wert den ersten dem Script übergebenen Parameter den. "-lt" steht für "less than " also "kleiner als". Entsprechend gibt es Vergleichsoperatoren wie „-gt“ (größer als), „-ge“ (größer gleich) oder „-eq“ (gleich). Ist die Bedingung nicht erfüllt, der Wert also größer oder gleich 10, führt das Script die Zeile unter „else“ aus. Andernfalls sorgt die Zeile unter „then“ dafür, dass die passende Meldung ausgegeben wird.
Der Code des nächsten Beispiels prüft, ob eine Datei vorhanden ist oder nicht:
if [ -e /etc/fstab ]; then echo " Datei vorhanden" else echo " Datei nicht vorhanden" fi
Die äußere Struktur ist die gleiche, wie beim vorherigen Beispiel. Zwischen „if“ und „fi“ ist die Abfrage eingebettet. Diesmal prüft der Ausdruck „-e /etc/fstab“, ob die angegebene Datei vorhanden ist.
Hinweis: Beachten Sie bei der Eingabe der Scripts die Leerzeichen vor und hinter den eckigen Klammern.
Mach's noch einmal: Schleifen in Bash
Für Schleifen stehen mehrere Bash-Kommandos zur Verfügung: while, until und for. Das Script
COUNTER=0 while [ $COUNTER -lt 10 ]; do echo "Der Zähler ist $COUNTER" let COUNTER=COUNTER+1 done
durchläuft die while/done-Struktur solange, wie die Bedingung „COUNTER < 10“ erfüllt ist. Nimmt COUNTER den Wert 10 an, ist das Script beendet. Das Script bringt also die Zahlen von 0 bis 9 auf den Bildschirm
Mit „until“ konstruieren Sie ähnliche Schleifen, nur dass dabei das Script läuft, bis die Bedingung erfüllt ist. Ein Beispiel sehen Sie im unteren Teil des Scripts in der Abbildung .
Ein wichtige Bedeutung haben Schleifen mit „for“. Die folgende Zeile Code nutzt „for“, um alle Großbuchstaben in Dateiname im aktuellen Verzeichnis in Kleinbuchstaben umzuwandeln.
for i in *; do mv $i $(echo $i | tr [:upper:] [:lower:]); done
Das ist vor allem nützlich, wenn Sie mit Microsoft Windows erstellte Dateien von einer Samba-Freigabe oder der Festplatte weiterverarbeiten möchten. Da das Betriebssystem aus Redmond die Groß- und Kleinschreibung nicht richtig beherrscht, liegen hier die Dateien meist in undefinierten Zuständen herum. Welche Dateinamen das Script verarbeitet ist mit „*“ (alle Dateien) bestimmt. Sie können hier auch "*.txt" einsetzen, um nur Dateien mit der Endung "txt" zu bearbeiten. Die Variable „$i“ nimmt innerhalb der do/done- Schleife nacheinander jeweils den Wert eines Dateinamens im aktuellen Verzeichnis an. „echo $i“ übergibt per Pipe („|“) die Namen an das Tool „tr“, das die Umwandlung der Zeichenketten erledigt. Beachten Sie, das der Ausdruck innerhalb einer Klammer mit vorangestelltem „$" steht. Das Ergebnis der Operation in der Klammer behandelt Bash dadurch wie eine Variable ("command substitution"). In älteren Scripten finden Sie den Ausdruck häufig von den Zeichen "`" (<Shift>-<Akzent>) umgeben. Das bewirkt das gleiche.
Übrigens : Wenn Sie die Parameter für „tr“ umdrehen, also „tr [:lower:] [:upper:]“ schreiben, wandelt das Script alle Dateinamen in Großbuchstaben um.
Mehr Struktur: Funktionen schreiben
Lange Bash-Scripte wirken schnell unübersichtlich. Mit Hilfe von Funktionen lassen sie sich aber leicht in kleinere Einheiten aufteilen. Funktionen dienen außerdem dazu, häufig wiederkehrende Abläufe nur einmal im Code unterbringen zu müssen. Ein Beispiel: Sie benötigen in einem Script die aktuelle IP Nummer des Rechners. Dazu verwenden Sie die Funktion
getip () {
MYIP=$(/sbin/ifconfig eth0 | awk '/inet/ { print $2 }' | awk -F ":" '{ print $2 }')
}
Das Programm awk dient hier zum Ausfiltern der für uns interessanten Bestandteile aus der Ausgabe von /sbin/ifconfig. Der erste akw-Aufruf ergibt beispielsweise "Adresse:192.168.0.1", das ist die zweite Zeichenkette („print $2“) hinter dem String „inet“. Der zweite awk-Aufruf ergibt den Wert hinter „:“, also „192.168.0.1". Sie rufen die Funktion im Script einfach mit ihrem Namen („getip“) auf, „echo $MYIP“ gibt das Resultat auf den Bildschirm aus.
Da Bash ein Script von oben nach unten interpretiert, müssen die Funktionen immer am Anfang stehen. Steht der Funktionsaufruf vor der Funktion, erhalten Sie eine Fehlermeldung.
Schöner Scripten: Dialoge für Bash
Auch wenn Sie selber den spröden Charme der Scripte auf der Kommandozeile schätzen und lieben gelernt haben, so steigt besonders bei der Weitergabe der Scripte an andere Anwender die Akzeptanz, wenn die Mausbedienung nicht ganz außen vor bleibt. Eine einfache Hinweis-Box mit Text und OK-Schaltfläche bringt unter KDE beispielsweise die Zeile
kdialog --msgbox "Meldung“
auf den Bildschirm. Es sind aber auch Listboxen, Ja/Nein-Boxen, Auswahlfelder und einiges mehr möglich (-> Kasten „Dialog: Die wichtigsten Parameter“).
Eine Demo der Möglichkeiten finden Sie in unserem Script simplebackupdialog.sh (-> Abbildung). Es entspricht dem Script simplebackup.sh , zusätzlich angereichert mit zwei Dialogen. Die Variable „DIALOG“ bestimmt das Dialogprogramm, in unserem Beispiel „kdialog“. Sie können hier auch „gdialog“ oder „dialog“ eintragen, je nach Bedarf. Den ersten Dialog ruft die Zeile
$DIALOG --title "Backup" --yesno "$M1" 10 60
auf. „--title“ legt den Dialogtitel fest. „--yesno“ ist der Dialogtyp, in unserem Fall ein Dialog mit den Schaltflächen „Ja“ und „Nein“. Die Werte am Ende der Zeile sind nur für „dialog“ von Bedeutung. Sie bestimmen Höhe und Breite des Dialogs im Terminal-Fensters.
Der Dialog gibt den Wert „0“ zurück, wenn der Anwender auf „Ja“ klickt. Bei „Nein“ ist der Wert „1“. Die Auswertung erfolgt über den Befehl „case $?“. Abhängig von der gedrückten Taste, führt das Script die Befehle hinter „0)“ oder „1)“ aus. Entscheidet sich der Anwender für „Ja“ führt der tar-Befehl die Sicherung durch. Anschließend sorgt der Befehl
$DIALOG --msgbox "$M2" 10 60
für die Ausgabe einer Meldung, die über das Ende des Backups informiert. Bei Aufruf des Scripts aus einem Konsolen-Fenster heraus, ist die Ausgabe von tar wie üblich auf dem Bildschirm zu sehen. Erfolgte der Start über Konqueror, arbeitet das Script still im Hintergrund.
((Bash_SimpleBackupDialog.png - 1,33 Spalten - BU))
Einfache Dialoge: Scripte müssen nicht nur im Terminalfenster laufen. Kdialog ermöglicht die Interaktion mit dem Anwender auch über die grafische Benutzeroberfläche
Internet: Bash und CGI-Scripts
Die bevorzugten Script-Sprachen bei der CGI-Programmierung (Common Gateway Interface) für Webserver sind sicher PHP, Perl oder Ptyhon. Es geht jedoch auch mit Bash. Besonders kleine, systemnahe Anwendungen sind damit schnell erstellt. Unser Beispielscript visits.sh (-> Abbildung) bietet einen einfachen Besucherzähler für eine Webseite. Zusätzlich gibt es Datum und Uhrzeit des Servers aus.
Für diesen Tipp setzen wir voraus, das auf Ihrem PC der Apache-Webserver installiert und gestartet ist. Kopieren Sie die Datei in das cgi-bin-Verzeichnis des Servers. Bei Suse 9.3 ist das /srv/www/cgi-bin. Machen Sie sie mit „chmod u+x visits.sh“ ausführbar, und starten Sie das Script einmal. Es erstellt dann die Dateien date.txt und counter.txt. date.txt enthält dann das aktuelle Datum und counter.txt den Zählerstand. Nach dem ersten Aufruf ist dieser "1". Bei jedem Aufruf liest das Script den aktuellen Zählerstand in die Variable "CURRENT" und erhöht den Wert in der Zeile
VISITOR=$(expr $CURRENT + 1)
jeweils um "1". Anschließend schreibt es den neuen Wert mit
echo "$VISITOR" > counter.txt
in die Datei counter.txt. Der Rest des Scripts dient der Ausgabe der Werte im HTML-Format, die letzten beiden Zeilen geben das aktuelle Datum und Uhrzeit aus.
Da das Script später mit den Rechten des Webservers läuft, müssen Sie mit
chown wwwrun.www visits.sh counter.txt date.txt
den Eigentümer der Dateien ändern. Sonst kann der Server den Inhalt der Dateien nicht ändern. Geben Sie im Browser die Adresse http://localhost/cgi-bin/visits.sh ein. Die Ausgabe des Scripts erscheint im Browserfenster.
Tipp: Das Script lässt sich nicht nur direkt aufrufen, sondern auch in HTML einbetten. Dazu fügen Sie in Ihre Start-Seite an der gewünschten Stelle die Zeile
ein. Bei diesem Aufruf handelt es sich um einen Server Side Include (SSI), den die meisten Webserver in der Standard-Konfiguration nicht verarbeiten. Der Server ignoriert die Anweisung dann einfach. Um das zu ändern, müssen Sie bei Suse Linux 9.3 in der Datei /etc/apache2/default-server.conf im Abschnitt „<Directory „/srv/www/htdocs“> die Zeile „Options None“ durch „Options Include“ ersetzen. Erstellen Sie im Verzeichnis /srv/www/htdocs die Datei .htaccess mit dem Inhalt
XBitHack on
und setzen Sie mit „chmod +x <Dateiname>“ das Ausführen-Attribut der HTML-Datei mit dem Script-Aufruf. Danach durchsucht der Apache-Server jede Ausführbare HTML-Datei nach Includes und führt diese - wenn vorhanden - aus.
Dialoge: Die wichtigsten Parameter
Scripte lassen sich auch über einer einfachen grafische Oberfläche steuern. Für das Terminalfenster gibt es das Programm „dialog“. Für KDE erfüllt „kdialog“ den gleichen Zweck. Bei Gnome heißt es „gdialog“. Die drei Programme verstehen in etwa die gleiche Syntax. „dialog“ ist meist standardmäßig installiert und bei Suse Linux 9.3 im Paket „dialog“ enthalten. „kdialog“ finden Sie beispielsweise bei Suse Linux 9.3 im Paket „kdebase", "gdialog" im Paket "zenity". Die wichtigsten Parameter für kdialog sind:
--yesno: Rückfrage mit Ja/Nein-Knöpfen --yesnocancel: Rückfrage mit Ja/Nein/Abbrechen-Knöpfen --error: Fehlermeldung --msgbox: Benachrichtigung --inputbox: Eingabefeld --textbox: Textfeld-Dialog --checklist: Ankreuzliste --radiolist: Auswahldialog --title: Dialog-Titel
Mehr Infos
Buch
Das deutschsprachiges Buch mit dem Titel "Shell-Script Programmierung" von Patrick Ditchen aus dem mitp-Verlag (39,95 Euro) und liefert eine Einführung in die Shell-Skript-Programmierung mit sh, ksh und bash, C-Shell und tcsh. Es ist auch für Einsteiger geeignet und dank zahlreiche Beispiele auch von direktem praktischen Nutzen.
Wer englischsprachige Bücher bevorzugt, greift am besten zu “Learning the bash Shell“ von Cameron Newham und Bill Rosenblatt aus dem O'Reilly-Verlag (32,50 Euro)
Internet
Im Internet gibt es zahlreiche Tutorials zum Thema Bash, der größte Teil allerdings in englischer Sprache. Eine kurze deutschsprachige Einführung finden Sie unter http://www.linuxfibel.de/bashprog.htm . Englischsprachige Anleitungen gibt es beispielsweise unter http://www.linuxselfhelp.com/HOWTO/Bash-Prog-Intro-HOWTO.html oder http://basicbash.activeventure.net .
Scripte zum Download
bashscripts.tar.gz enthält:
hello.sh
simplebackup.sh
schleifen.sh
simplebackupdialog.sh
getip.sh
visits.sh
convert.sh




