Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
Shell-Programmierung von Jürgen Wolf
Einführung, Praxis, Referenz
Buch: Shell-Programmierung

Shell-Programmierung
782 S., mit CD, 44,90 Euro
Rheinwerk Computing
ISBN 3-89842-683-1
gp Kapitel 1 Einführung
  gp 1.1 Voraussetzungen an den Leser
    gp 1.1.1 Zielgruppe
    gp 1.1.2 Notation
  gp 1.2 Was ist eine Shell?
  gp 1.3 Hauptanwendungsgebiet
    gp 1.3.1 Was ist ein Shellscript?
    gp 1.3.2 Vergleich mit anderen Sprachen
  gp 1.4 Kommando, Programm oder Shellscript?
    gp 1.4.1 Shell-eigene Kommandos (Builtin-Kommando)
    gp 1.4.2 Aliase in der Shell
    gp 1.4.3 Funktionen in der Shell
    gp 1.4.4 Shellscripts (Shell-Prozeduren)
    gp 1.4.5 Programme (binär)
  gp 1.5 Die Shell-Vielfalt
    gp 1.5.1 ksh (Korn-Shell)
    gp 1.5.2 Bash (Bourne-Again-Shell)
    gp 1.5.3 zsh (Z-Shell)
    gp 1.5.4 ash (A-Shell)
    gp 1.5.5 rbash, rzsh (Restricted Shell)
    gp 1.5.6 tcsh (TC-Shell)
    gp 1.5.7 Welche Shell-Variante wird in diesem Buch verwendet?
    gp 1.5.8 rsh und ssh
  gp 1.6 Betriebssysteme
  gp 1.7 Crashkurs: einfacher Umgang mit der Kommandozeile
    gp 1.7.1 Grundlegende Befehle
    gp 1.7.2 Der Umgang mit Dateien
    gp 1.7.3 Der Umgang mit Verzeichnissen
    gp 1.7.4 Datei- und Verzeichnisnamen
    gp 1.7.5 Gerätenamen
    gp 1.7.6 Dateiattribute
  gp 1.8 Shellscripts schreiben und ausführen
    gp 1.8.1 Der Editor
    gp 1.8.2 Der Name des Shellscripts
    gp 1.8.3 Ausführen
    gp 1.8.4 Hintergrundprozess starten
    gp 1.8.5 Ausführende Shell festlegen
    gp 1.8.6 Kommentare
    gp 1.8.7 Stil
    gp 1.8.8 Ein Shellscript beenden
    gp 1.8.9 Testen und Debuggen von Shellscripts
    gp 1.8.10 Shellscript, das ein Shellscript erstellt und ausführt
  gp 1.9 Vom Shellscript zum Prozess
    gp 1.9.1 Ist das Shellscript ein Prozess?
    gp 1.9.2 Echte Login-Shell?
  gp 1.10 Datenstrom
    gp 1.10.1 Ausgabe umleiten
    gp 1.10.2 Standardfehlerausgabe umleiten
    gp 1.10.3 Eingabe umleiten
    gp 1.10.4 Pipes
    gp 1.10.5 Ein T-Stück mit tee
    gp 1.10.6 Ersatzmuster (Wildcards)
    gp 1.10.7 Brace Extension (Bash und Korn-Shell only)
    gp 1.10.8 Muster-Alternativen (Bash und Korn-Shell only)
    gp 1.10.9 Tilde-Expansion (Bash und Korn-Shell only)
  gp 1.11 Empfehlung


Rheinwerk Computing

1.8 Shellscripts schreiben und ausführen  downtop

Sie finden hier eine Anleitung, wie Sie gewöhnlich vorgehen können, um eigene Shellscripts zu schreiben und auszuführen.


Rheinwerk Computing

1.8.1 Der Editor  downtop

Zu Beginn steht man immer vor der Auswahl seines Werkzeugs. In der Shell-Programmierung reicht hierfür der einfachste Editor aus. Welchen Editor Sie verwenden, hängt häufig vom Anwendungsfall ab. Obgleich ich hier ein Buch zur Shellscript-Programmierung schreibe, gestehe ich, kein großer Fan der Editoren »vi« und »emacs« zu sein. Ich verwende, wenn irgend möglich, einen Editor einer grafischen Oberfläche wie »Kate« unter KDE, »Gedit« unter dem GNOME-Desktop oder »xemacs« auf einer X11-Oberfläche.

Trotzdem habe ich die Mühe nicht gescheut, den gewöhnungsbedürftigen Umgang mit den quasi überall vorhandenen Editoren wie »vi«, »emacs«, »joe« oder »pico« zu erlernen. Der Grund ist ganz einfach: Als Systemadministrator oder Webmaster (mit Zugang über SSH) haben Sie nicht überall die Möglichkeit, auf eine grafische Oberfläche zurückzugreifen. Häufig sitzen Sie dann vor einem Rechner mit einer nackten Shell. Wenn Sie dann nicht wenigstens den grundlegenden Umgang mit (mindestens) »vi« beherrschen, sehen Sie ziemlich alt aus. Zwar besteht meistens noch die Möglichkeit eines Fernzugriffs zum Kopieren mit dem Kommando scp, aber macht man hier bspw. einen Tippfehler, ist dieser Vorgang auf Dauer eher ineffizient. Letztendlich ist das Ihre Entscheidung.


Rheinwerk Computing

1.8.2 Der Name des Shellscripts  downtop

Den Namen des Shellscripts, unter dem Sie dieses mit dem Editor Ihrer Wahl abspeichern, können Sie fast willkürlich wählen. Sie müssen lediglich folgende Punkte beachten:

gp  Es darf kein Name verwendet werden, von dem es ein Kommando mit demselben Namen gibt (das geht, aber man sollte es nicht machen). Dies können Sie relativ einfach testen, indem Sie etwa das Kommando which mit dem Namen Ihres Scripts verwenden (bspw. which scriptname). which liefert, falls es ein Kommando mit dem Namen gibt, den Pfad zum entsprechenden Kommando zurück. Gibt which nichts zurück, scheint ein solches Kommando nicht auf dem System zu existieren. Ähnliches kann auch mit type oder man vorgenommen werden.
gp  Sie sollten nur die Zeichen A bis Z, a bis z, 0 bis 9 und _ verwenden. Auf jeden Fall sollten Sonderzeichen vermieden werden.

Tipp   Auch wenn Sie Ihr Kommando (fast) nennen können wie Sie wollen, sollten Sie auf jeden Fall versuchen, einen Namen zu wählen, der einen Sinn ergibt.



Rheinwerk Computing

1.8.3 Ausführen  downtop

Das folgende Listing stellt Ihr erstes Shellscript in diesem Buch dar. Es ist ein einfaches Script, welches das aktuelle Datum anzeigt, als »wer« Sie sich eingeloggt haben, wer sich noch alles zurzeit auf dem System befindet und welchen Rechnernamen (Host) Sie verwenden. Im Augenblick ist es allerdings noch nicht so wichtig für Sie zu wissen, was das Shellscript genau macht (auch wenn es eigentlich nicht kompliziert ist). Hier geht es nur um die Ausführung eines Shellscripts. Tippen Sie das Beispiel in den Editor Ihrer Wahl und speichern Sie es ab (im Beispiel wurde der Name userinfo verwendet).

# Script-Name: userinfo
# zeigt das aktuelle Datum an
date
# gibt die Textfolge "Ich bin ..." aus
echo "Ich bin ..."
# Wer bin ich ... ?
whoami
echo "Alle User, die eingeloggt sind ..."
# zeigt alle aktiven User an
who
echo "Name des Host-Systems ..."
# gibt den Hostnamen (Rechnernamen) aus
hostname

Hinweis   Natürlich müssen Sie hier nicht alles abtippen. Sie finden alle Shellscripts auch auf der Buch-CD. Dennoch ist es aus Übungsgründen zu empfehlen, die meisten Shellscripts selbst zu schreiben, um ein Gefühl dafür zu bekommen.


Bevor Sie Ihr erstes Script ausführen können, müssen Sie gewöhnlich noch das Ausführrecht setzen. In Ihrem Fall ist dies das Ausführrecht (x) für den User (Dateieigentümer):

you@host > ls -l userinfo
-rw-r--r--  1 you users 286 2005–01–21 02:19 userinfo
you@host > chmod u+x userinfo
you@host > ls -l userinfo
-rwxr--r--  1 you users 286 2005–01–21 02:19 userinfo

Hinweis   Wenn Ihnen die oktale Schreibweise etwas geläufiger ist, können Sie selbstverständlich auch chmod damit beauftragen, das Ausführrecht zu setzen: chmod 0744 userinfo


Jetzt können Sie das Script beim Namen aufrufen. Allerdings werden Sie gewöhnlich den absoluten Pfadnamen verwenden müssen, es sei denn, Sie fügen das entsprechende Verzeichnis (wo sich das Script befindet) zur Umgebungsvariablen PATH hinzu (aber dazu später mehr). Somit lautet ein möglicher Aufruf des Scripts wie folgt:

you@host > ./userinfo
Fr Jan 21 02:35:06 CET 2005
Ich bin ...
you
Alle User, die eingeloggt sind ...
you    :0           Jan 20 23:06 (console)
ingo   :0           Jan 20 12:02 (console)
john   pts/0        Jan  1 16:15 (pd9e9bdc0.dip.t-dialin.net)
john   pts/2        Jan  1 16:22 (pd9e9bdc0.dip.t-dialin.net)
Name des Host-Systems ...
goliath.speedpartner.de

Hier wird mit ./ das aktuelle Verzeichnis verwendet. Starten Sie das Script aus einem anderen Verzeichnis, müssen Sie eben den absoluten Pfadnamen angeben:

you@host:~/irgend/wo > /home/tot/beispielscripte/Kap1/userinfo

Damit Sie verstehen, wie ein Shellscript ausgeführt wird, muss ich Ihnen leider noch ein Shellscript aufdrücken, bevor Sie mit den eigentlichen Grundlagen der Shell beginnen können. Es ist nämlich von enormer Bedeutung, dass Sie verstehen, dass nicht die aktuelle Shell das Script ausführt. Zum besseren Verständnis:

you@host > ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
you       3672  3658  0 Jan20 pts/38   00:00:00 /bin/bash
you       7742  3672  0 03:03 pts/38   00:00:00 ps -f

Sie geben hier mit ps –f die aktuelle Prozessliste (hier unter Linux mit der Bash) der Shell auf den Bildschirm aus. Hier lautet die Prozessnummer (PID) der aktuellen Shell 3672. Die Nummer des Elternprozesses (PPID), der diese Shell gestartet hat, lautet hierbei 3658. Im Beispiel war dies der Dämon »kdeinit«, was hier allerdings jetzt nicht von Bedeutung ist. Den Prozess ps –f haben Sie ja soeben selbst gestartet und anhand der PPID lässt sich auch hier ermitteln, von welcher Shell dieser Prozess gestartet wurde (hier 3672, also der aktuellen Bash).

Um Ihnen jetzt zu demonstrieren, wie ein Shellscript ausgeführt wird, führen Sie bitte folgendes Script aus:

# Script-Name: finduser
# gibt alle Dateien des Users you auf dem Bildschirm aus
find / -user you -print 2>/dev/null

Ich habe hier bewusst einen Befehl verwendet, der ein wenig länger beschäftigt sein sollte. Mit dem Kommando find und den entsprechenden Angaben werden alle Dateien des Users »you« unterhalb des Wurzelverzeichnisses / auf dem Bildschirm ausgegeben. Fehlerausgaben (Kanal 2) wie bspw. »keine Berechtigung« werden nach /dev/null umgeleitet und somit nicht auf dem Bildschirm ausgegeben. Auf das Thema Umleitung wird noch gezielt eingegangen. Damit uns im Beispiel hier nicht die Standardausgabe (Kanal 1) auf dem Bildschirm stört, leiten wir diese auch beim Start des Scripts nach /dev/null (1>/dev/null) um. Und damit uns die Shell für weitere Eingaben zur Verfügung steht, stellen wir die Ausführung des Scripts in den Hintergrund (&). Somit können Sie in aller Ruhe die Prozessliste betrachten, während Sie das Script ausführen.

you@host > chmod u+x finduser
you@host > ./finduser 1>/dev/null &
[1] 8138
you@host > ps -f
UID   PID  PPID  C STIME TTY         TIME CMD
you  3672  3658  0 Jan20 pts/38  00:00:00 /bin/bash
you  8138  3672  0 03:26 pts/38  00:00:00 /bin/bash
you  8139  8138 10 03:26 pts/38  00:00:00 find / -user tot -print
you       8140  3672  0 03:26 pts/38   00:00:00 ps -f
you@host > kill $!
[1]+  Beendet                 ./finduser >/dev/null

Damit das Script nicht im Hintergrund unnötig Ressourcen verbraucht, wurde es mit kill $! beendet. Die Zeichenfolge »$!« ist eine Shell-Variable einer Prozessnummer vom zuletzt gestarteten Hintergrundprozess (auch hierauf wird noch eingegangen). Interessant ist für diesen Abschnitt nur die Ausgabe von ps –f:

UID   PID  PPID  C STIME TTY         TIME CMD
tot  3672  3658  0 Jan20 pts/38  00:00:00 /bin/bash
tot  8138  3672  0 03:26 pts/38  00:00:00 /bin/bash
tot  8139  8138 10 03:26 pts/38  00:00:00 find / -user tot -print
tot  8140  3672  0 03:26 pts/38  00:00:00 ps -f

Sie können hier anhand der PPID erkennen, dass von der aktuellen Shell (PID:3672) eine weitere Shell (8138) gestartet wurde. Bei dieser neuen Shell spricht man von einer Subshell. Erst diese Subshell führt anschließend das Script aus, wie unschwer anhand der PPID von find zu erkennen ist. Der Befehl ps –f hingegen wurde wiederum von der aktuellen Shell ausgeführt.

Derselbe Vorgang ist natürlich auch bei der Bourne-Shell (sh) und der Korn-Shell (ksh) möglich und nicht nur, wie hier gezeigt, unter der bash. Jede Shell ruft für das Ausführen eines Scripts immer eine Subshell auf. Die bash eine bash und die sh eine sh. Nur bei der Korn-Shell kann es sein, dass anstatt einer weiteren ksh eine sh aufgerufen wird! Wie Sie dies ermitteln können, haben Sie ja eben erfahren.


Rheinwerk Computing

1.8.4 Hintergrundprozess starten  downtop

Wie Sie beim Ausführen des Beispiels eben entnehmen konnten, können Sie durch das Anhängen eines Ampersand-Zeichens (&) den Prozess im Hintergrund ausführen. Dies wird gerade bei Befehlen verwendet, die etwas länger im Einsatz sind. Würden Sie im Beispiel von finduser den Prozess im Vordergrund (also normal) ausführen, müssten Sie auf das Ende des Prozesses warten, bis Ihnen der Eingabeprompt der aktuell ausführenden Shell wieder zur Verfügung steht. Dadurch, dass der Prozess in den Hintergrund gestellt wird, können Sie weitere Prozesse quasi parallel starten.


Rheinwerk Computing

1.8.5 Ausführende Shell festlegen  downtop

Im Beispiel konnten Sie sehen, dass ich das Script in einer Bash als (Sub-)Shell ausgeführt habe. Was aber, wenn ich das Script gar nicht in der Bash ausführen will? Schreiben Sie bspw. ein Shellscript in einer bestimmten Shell-Syntax, werden Sie wohl auch wollen, dass Ihr Script eben in der entsprechenden (Sub-)Shell ausgeführt wird. Hierbei können Sie entweder die (Sub-)Shell direkt mit dem Shellscript als Argument aufrufen oder eben die auszuführende (Sub-)Shell im Script selbst festlegen.

Aufruf als Argument der Shell

Der Aufruf eines Shellscripts als Argument der Shell ist recht einfach zu bewerkstelligen:

you@host > sh finduser

Hier wird zum Ausführen des Shellscripts die Bourne-Shell (sh) als Subshell verwendet. Wollen Sie hingegen das Script mit einer Korn-Shell als Subshell aufrufen, rufen Sie das Script wie folgt auf:

you@host > ksh finduser

Ebenso können Sie auch andere Shells wie bspw. ash oder zsh verwenden. Natürlich können Sie auch testweise eine C-Shell (bspw. tcsh) aufrufen – um festzustellen, dass hier schon erste Unstimmigkeiten auftreten.

Ausführende Shell im Script festlegen (She-Bang-Zeile)

Letztendlich besteht der gewöhnliche Weg darin, die ausführende Shell im Script selbst festzulegen. Dabei muss sich in der ersten Zeile des Shellscripts die Zeichenfolge #! gefolgt von der absoluten Pfadangabe der entsprechenden Shell befinden (wird auch als She-Bang-Zeile bezeichnet). Die absolute Pfadangabe können Sie einfach mittels which ermitteln. Gewöhnlich befinden sich alle Shell-Varianten im Verzeichnis /bin oder in /usr/bin (bzw. /usr/local/bin ist auch ein Kandidat).

Wollen Sie bspw. das Shellscript finduser von einer Korn-(Sub-)Shell ausführen lassen, müssen Sie in der ersten Zeile Folgendes eintragen:

#!/bin/ksh

oder

#!/usr/bin/ksh

Somit sieht das komplette Script für die Korn-Shell so aus (davon ausgehend, dass sich die Korn-Shell in /bin befindet):

#!/bin/ksh
# Shellscript: finduser
# gibt alle Dateien des Users tot auf dem Bildschirm aus
find / -user tot -print 2>/dev/null

Für die Bash verwenden Sie:

#!/bin/bash

oder

#!/usr/bin/bash

Und für die Bourne-Shell:

#!/bin/sh

oder

#!/usr/bin/sh

Ähnlich wird diese erste Zeile übrigens auch bei Perl und anderen Skriptsprachen verwendet. Das dies funktioniert, ist nichts Magisches, sondern ein typischer Linux-UNIX-Vorgang. Beim Start eines neuen Programms (besser ist wohl Prozess) verwenden alle Shell-Varianten den Linux-UNIX-Systemaufruf exec. Wenn Sie aus der Login-Shell eine weitere Prozedur starten, wird ja zunächst eine weitere Subshell gestartet (wie bereits erwähnt). Durch den Systemaufruf exec wird der neue Prozess durch ein angegebenes Programm überlagert – egal ob dieses Programm jetzt in Form einer ausführbaren Datei (wie diese etwa in C erstellt werden) oder als Shellscript vorhanden ist. Im Fall eines Shellscripts startet exec standardmäßig eine Shell vom Typ Ihrer aufrufenden Shell und beauftragt diese Shell, alle Befehle und Kommandos der angegebenen Datei auszuführen. Enthält das Shellscript allerdings in der ersten Zeile eine Angabe wie

#! Interpreter [Argument(e)]

verwendet exec den vom Script angegebenen Interpreter zum Ausführen des Shellscripts. Als Interpreter können alle Ihnen bekannten Shell-Varianten (sofern auf dem System vorhanden) verwendet werden (wie bereits erwähnt, nicht nur eine Shell!).

An der Zeichenfolge #! in der ersten Zeile erkennt exec die Interpreterzeile und verwendet die dahinter stehenden Zeichen als Namen des Programms, das als Interpreter verwendet werden soll. Der Name Ihres Shellscripts wird beim Aufruf des Interpreters automatisch übergeben. Dieser exec-Mechanismus wird von jeder Shell zum Aufrufen eines Programms oder Kommandos verwendet. Somit können Sie sichergehen, dass der Ablauf Ihres Scripts in der richtigen Umgebung ausgeführt wird, auch wenn Sie es gewohnt sind, in einer anderen Shell zu arbeiten.


Hinweis   Es sollte Ihnen klar sein, dass hinter dem Interpreternamen kein weiterer Kommentar folgen darf, weil dieser sonst als Argument verwendet würde.


Shellscript ohne Subshell ausführen

Es ist auch möglich, ein Shellscript ohne das vorherige Starten einer Subshell auszuführen, um es direkt von der aktuellen Shell ausführen zu lassen. Hierzu muss dem Shellscript beim Starten lediglich ein Punkt plus Leerzeichen vorangestellt werden. Dieser Vorgang wird bspw. verwendet, wenn Sie im Script Veränderungen an den (Umgebungs-)Variablen wollen. Würden Sie Ihr Script hierbei in der Subshell ausführen, so würden sich alle Veränderungen nur auf alle weiteren Aktionen der Subshell beziehen. Wenn sich die Subshell beendet, sind auch alle Änderungen an (Umgebungs-)Variablen weg.


Hinweis   Vielleicht haben Sie schon mal gehört, dass man dem Inhalt von Umgebungsvariablen nicht unbedingt trauen sollte – denn jeder kann diese verändern. In diesem Fall ist es noch schlimmer, denn zum Ausführen eines Shellscripts mit einem Punkt davor benötigt der Benutzer nicht einmal Ausführrechte. Hierbei begnügt sich die Shell schon mit dem Leserecht, um munter mitzumachen.


Ein Beispiel, wie Sie ein Shellscript ohne Subshell ausführen können:

you@host > . ./script_zum_ausfuehren

oder mit absoluten Pfadnamen:

you@host > . /home/tot/beispielscripte/Kap1/script_zum_ausfuehren

Hinweis   Die Bash kennt als Alternative zum Punkt das interne Kommando source.



Rheinwerk Computing

1.8.6 Kommentare  downtop

In den Scripts zuvor wurden Kommentare bereits reichlich verwendet, und Sie sollten dies in Ihren Scripts auch regelmäßig tun. Einen Kommentar können Sie durch ein vor dem Text stehendes Hash-Zeichen (#) erkennen. Hier ein Beispiel, wie Sie Ihre Scripts kommentieren können:

#!/bin/sh
# Script-Name: HalloWelt
# Version    : 0.1
# Autor      : J.Wolf
# Datum      : 20.05.2005
# Lizenz     : ...
# ... gibt "Hallo Welt" aus
echo "Hallo Welt"
echo "Ihre Shell:"
echo $SHELL           # ... gibt die aktuelle Shell aus

Zugegeben, für ein solch kleines Beispiel sind die Kommentare ein wenig übertrieben. Sie sehen hier, wie Sie auch Kommentare hinter einen Befehl setzen können. Alles, was hinter einem Hash-Zeichen steht, wird von der Shell ignoriert. Natürlich mit Ausnahme der ersten Zeile, wenn sich dort die Zeichenfolge »#!« befindet.

Kommentieren sollten Sie zumindest den Anfang des Scripts mit einigen Angaben zum Namen und eventuell dem Zweck, sofern dieser nicht gleich klar sein sollte. Wenn Sie wollen, können Sie selbstverständlich auch Ihren Namen, das Datum und die Versionsnummer angeben. Auch auf Besonderheiten bezüglich einer Lizenz sollten Sie hier hinweisen. Komplexe Stellen sollten auf jeden Fall ausreichend kommentiert werden. Dies hilft Ihnen, den Code nach längerer Abwesenheit schneller wieder zu verstehen. Sofern Sie die Scripts der Öffentlichkeit zugänglich machen wollen, wird man es Ihnen danken, wenn Sie Ihren »Hack« ausreichend kommentiert haben.


Rheinwerk Computing

1.8.7 Stil  downtop

Jeder Programmierer entwickelt mit der Zeit seinen eigenen Programmierstil, dennoch gibt es einiges, was Sie vielleicht beachten sollten. Zwar ist es möglich, durch ein Semikolon getrennt mehrere Befehle in einer Zeile zu schreiben (wie dies ja in der Shell selbst auch möglich ist), doch sollten Sie dies, wenn möglich, der Übersichtlichkeit zuliebe vermeiden.

Und sollte eine Zeile doch mal ein wenig zu lang werden, dann können Sie immer noch das Backslash-Zeichen (\) setzen. Ein Shellscript arbeitet ja Zeile für Zeile ab. Als Zeilentrenner wird gewöhnlich das Newline-Zeichen (ein für den Editor nicht sichtbares Zeichen mit der ASCII-Code-Nummer 10) verwendet. Durch das Voranstellen eines Backslash-Zeichens wird das Newline-Zeichen außer Kraft gesetzt.

#!/bin/sh
# Script-Name: backslash
# ... bei überlangen Befehlen kann man ein Backslash setzen
echo "Hier ein solches Beispiel, wie Sie\
 ueberlange Zeilen bzw. Ketten von Befehlen\
 auf mehreren Zeilen ausführen können"

Bei etwas überlangen Ketten von Kommandos verhilft das Setzen eines Backslashs auch ein wenig, die Übersichtlichkeit zu verbessern:

ls -l /home/tot/docs/listings/beispiele/kapitel1/final/*.sh | \
    sort -r | less

Wenn Sie etwas später auf Schleifen und Verzweigungen treffen, sollten Sie gerade hier mal eine Einrückung mehr als nötig vornehmen. Einmal mehr auf die (ÿ_)-Taste zu drücken, hat noch keinem geschadet.


Rheinwerk Computing

1.8.8 Ein Shellscript beenden  downtop

Ein Shellscript beendet sich entweder nach Ablauf der letzten Zeile selbst oder Sie verwenden den Befehl exit, womit die Ausführung des Scripts sofort beendet wird. Die Syntax des Kommandos sieht wie folgt aus:

exit [n]

Der Parameter n ist optional. Für diesen Wert können Sie eine ganze Zahl von 0 bis 255 verwenden. Verwenden Sie exit ohne jeden Wert, wird der exit-Status des Befehls genutzt, der vor exit ausgeführt wurde. Mit den Werten 0 bis 255 wird angegeben, ob ein Kommando oder Script ordnungsgemäß ausgeführt wurde. Der Wert 0 steht dafür, dass alles ordnungsgemäß abgewickelt wurde. Jeder andere Wert signalisiert eine Fehlernummer.

Sie können damit auch testen, ob ein Kommando, das Sie im Script ausgeführt haben, erfolgreich ausgeführt wurde und je nach Situation das Script an einer anderen Stelle fortsetzen lassen. Hierfür fehlt Ihnen aber noch die Kenntnis der Verzweigung. Die Zahl des exit-Status kann jederzeit mit der Shell-Variablen $? abgefragt werden. Hierzu ein kurzes Beispiel:

#!/bin/sh
# Script-Name: ende
echo "Tick ..."
# ... Shellscript wird vorzeitig beendet
exit 5
# "Tack ..." wird nicht mehr ausgeführt
echo "Tack ...

Das Beispiel bei der Ausführung:

you@host > chmod u+x ende
you@host > ./ende
Tick ...
you@host > echo $?
5
you@host > ls -l /root
/bin/ls: /root: Keine Berechtigung
you@host > echo $?
1
you@host > ls -l *.txt
/bin/ls: *.txt: Datei oder Verzeichnis nicht gefunden
you@host > echo $?
1
you@host > ls -l *.c
-rw-r--r--  1 tot users 49 2005–01–22 01:59 hallo.c
you@host > echo $?
0

Im Beispiel wurden auch andere Kommandos ausgeführt. Je nach Erfolg war hierbei der Wert der Variablen $? 1 (bei einem Fehler) oder 0 (wenn alles in Ordnung ging) – abgesehen von unserem Beispiel, wo bewusst der Wert 5 zurückgegeben wurde.


Hinweis   Beachten Sie bitte, wenn Sie den Befehl exit direkt im Terminal ausführen, wird dadurch auch die aktuelle Login-Shell beendet.



Rheinwerk Computing

1.8.9 Testen und Debuggen von Shellscripts  downtop

Debuggen und Fehlersuche ist auch in der Shellscript-Programmierung von großer Bedeutung, sodass diesem Thema ein extra Abschnitt gewidmet wird. Trotzdem werden Sie auch bei Ihren ersten Scripts unweigerlich den einen oder anderen (Tipp-)Fehler einbauen (es sei denn, Sie verwenden sämtliche Listings von der Buch-CD).

Am häufigsten wird dabei in der Praxis die Option –x verwendet. Damit wird jede Zeile vor ihrer Ausführung auf dem Bildschirm ausgegeben. Meistens wird diese Zeile mit einem führenden Plus angezeigt (abhängig davon, was in der Variablen PS4 enthalten ist). Als Beispiel diene folgendes Shellscript:

#!/bin/sh
# Script-Name: prozdat
# Listet Prozessinformationen auf
echo "Anzahl laufender Prozesse:"
# ... wc -l zählt alle Zeilen, die ps -ef ausgeben würde
ps -ef | wc -l
echo "Prozessinformationen unserer Shell:"
# ... die Shell-Variable $$ enthält die eigene Prozessnummer
ps $$

Normal ausgeführt ergibt dieses Script folgende Ausgabe:

you@host > ./prozdat
Anzahl laufender Prozesse:
76
Prozessinformationen unserer Shell:
  PID TTY      STAT   TIME COMMAND
10235 pts/40   S+     0:00 /bin/sh ./prozdat

Auch hier wollen wir uns zunächst nicht zu sehr mit dem Script selbst befassen. Jetzt soll die Testhilfe mit der Option –x eingeschaltet werden:

you@host > sh -x ./prozdat
+ echo 'Anzahl laufender Prozesse:'
Anzahl laufender Prozesse:
+ ps -ef
+ wc -l
76
+ echo 'Prozessinformationen unserer Shell:'
Prozessinformationen unserer Shell:
+ ps 10405
  PID TTY      STAT   TIME COMMAND
10405 pts/40   S+     0:00 sh -x ./prozdat

Sie sehen, wie jede Zeile vor ihrer Ausführung durch ein voranstehendes Plus ausgegeben wird. Außerdem können Sie hierbei auch feststellen, dass die Variable $$ durch den korrekten Inhalt ersetzt wurde. Selbiges wäre übrigens auch bei der Verwendung von Sonderzeichen (Wildcards) wie * der Fall. Sie bekommen mit dem Schalter –x alles im Klartext zu sehen.

Bei längeren Scripts ist mir persönlich das Pluszeichen am Anfang nicht deutlich genug. Wenn Sie dies auch so empfinden, können Sie die Variable PS4 gegen eine andere beliebige Zeichenkette austauschen. Ich verwende hierfür sehr gern die Variable LINENO, die nach der Ausführung immer durch die entsprechende Zeilennummer ersetzt wird. Die Zeilennummer hilft mir dann bei längeren Scripts, immer gleich die entsprechende Zeile zu finden. Hier ein Beispiel, wie Sie mit PS4 effektiver Ihr Script debuggen können:

you@host > export PS4='[--- Zeile: $LINENO ---] '
you@host > sh -x ./prozdat
[--- Zeile: 6 ---] echo 'Anzahl laufender Prozesse:'
Anzahl laufender Prozesse:
[--- Zeile: 8 ---] ps -ef
[--- Zeile: 8 ---] wc -l
76
[--- Zeile: 10 ---] echo 'Prozessinformationen unserer Shell:'
Prozessinformationen unserer Shell:
[--- Zeile: 12 ---] ps 10793
  PID TTY      STAT   TIME COMMAND
10793 pts/40   S+     0:00 sh -x ./prozdat

Rheinwerk Computing

1.8.10 Shellscript, das ein Shellscript erstellt und ausführt  toptop

Hand aufs Herz: Wie oft haben Sie bis hierher schon einen Fluch ausgestoßen, weil Sie bspw. vergessen haben, das Ausführrecht zu setzen, oder waren davon genervt, immer wiederkehrende Dinge zu wiederholen? Dazu lernen Sie ja eigentlich Shellscript-Programmierung, nicht wahr? Somit liegt nichts näher, als Ihnen hier eine kleine Hilfe mitzugeben. Ein Shellscript, welches ein neues Script erstellt oder ein bereits vorhandenes Script in den Editor Ihrer Wahl lädt. Natürlich soll auch noch das Ausführrecht für den User gesetzt werden und bei Bedarf wird das Script ausgeführt. Hier das simple Script:

# Ein Script zum Script erstellen ...
# Name : scripter
# Bitte entsprechend anpassen
#
# Verzeichnis, in dem sich das Script befindet
dir=$HOME
# Editor, der verwendet werden soll
editor=vi
# erstes Argument muss der Scriptname sein ...
[ -z "$1" ] && exit 1
# Editor starten und Script laden (oder erzeugen)
$editor $dir/$1
# Ausführrechte für User setzen ...
chmod u+x $dir/$1
# Script gleich ausführen? Nein? Dann auskommentieren ...
$dir/$1

Sie müssen bei diesem Script lediglich die Variablen »dir« und »editor« anpassen. Mit der Variable »dir« geben Sie das Verzeichnis an, wohin das Script geladen oder eventuell abgespeichert werden soll. Im Beispiel wurde einfach mit der Shell-Variablen HOME das Heimverzeichnis des eingeloggten Users verwendet. Als Editor verwende ich vi. Hier können Sie auch einen Editor Ihrer Wahl eintragen. Mit [ –z "$1" ] (z steht für zero, also leer) wird überprüft, ob das erste Argument der Kommandozeile ($1) vorhanden ist. Wurde hier keine Angabe gemacht, beendet sich das Script gleich wieder mit exit 1. Die weitere Ausführung spricht, glaube ich, erst einmal für sich. Aufgerufen wird das Script wie folgt:

you@host > ./scripter example

Natürlich ist es nicht meine Absicht, dem Einsteiger mit diesem Script eine Einführung in die Shellscript-Programmierung zu geben, sondern hier geht es nur darum, Ihnen eine kleine Hilfe an die Hand zu geben, um effektiver mit dem Buch arbeiten zu können.

Nachdem bis hierhin alle Formalitäten geklärt wurden, können Sie endlich damit loslegen, die eigentliche Shellscript-Programmierung zu erlernen. Zugegeben, es waren viele Formalitäten, aber dies war aus meiner Sicht unbedingt nötig.



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen.

>> Zum Feedback-Formular
 << zurück
  
  Zum Katalog
Zum Katalog: Shell-Programmierung
Shell-Programmierung
bestellen
 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-Server






 Linux-Server


Zum Katalog: Das Komplettpaket LPIC-1 & LPIC-2






 Das Komplettpaket
 LPIC-1 & LPIC-2


Zum Katalog: Linux-Hochverfügbarkeit






 Linux-
 Hochverfügbarkeit


Zum Katalog: Linux Handbuch






 Linux Handbuch


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2005
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern