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 6 Funktionen
  gp 6.1 Definition
    gp 6.1.1 Definition (Bash und Korn-Shell only)
    gp 6.1.2 Funktionsaufruf
    gp 6.1.3 Funktionen exportieren
    gp 6.1.4 Aufrufreihenfolge
    gp 6.1.5 Who is who
    gp 6.1.6 Aufruf selbst bestimmen
    gp 6.1.7 Funktionen auflisten
  gp 6.2 Funktionen, die Funktionen aufrufen
  gp 6.3 Parameterübergabe
    gp 6.3.1 FUNCNAME (Bash only)
  gp 6.4 Rückgabewert aus einer Funktion
    gp 6.4.1 Rückgabewert mit return
    gp 6.4.2 Rückgabewert mit echo und einer Kommando-Substitution
    gp 6.4.3 Rückgabewert ohne eine echte Rückgabe (lokale Variable)
    gp 6.4.4 Funktionen und exit
  gp 6.5 Lokale contra globale Variablen
    gp 6.5.1 Lokale Variablen (Bash und Korn-Shell only)
  gp 6.6 alias und unalias
  gp 6.7 Autoload (Korn-Shell only)

Kapitel 6 Funktionen

Je länger die Shellscripts in den vorangegangenen Kapiteln wurden, umso unübersichtlicher wurden sie. Verwendete man dann auch noch die Routinen mehrmals im Script, so steigerte sich der Umfang weiter. In solch einem Fall (und eigentlich fast immer) sind Funktionen die Lösung. Mit Funktionen fassen Sie mehrere Befehle in einem Block zwischen geschweiften Klammern zusammen und rufen sie bei Bedarf mit einem von Ihnen definierten Funktionsnamen auf. Eine einmal definierte Funktion können Sie jederzeit in Ihrem Script mehrmals aufrufen und verwenden. Funktionen sind somit auch Scripts, welche in der laufenden Umgebung des Shell-Prozesses immer präsent sind, und verhalten sich folglich, als seien Sie interne Shell-Kommandos.


Rheinwerk Computing

6.1 Definitiodowntop

Wenn Sie eine Shell-Funktion schreiben, wird diese zunächst nicht vom Shell-Prozess ausgeführt, sondern zunächst in der laufenden Umgebung gespeichert (genauer, die Funktion wird hiermit definiert). Mit folgender Syntax können Sie eine Funktion definieren:

funktions_name() {
   kommando1
   kommando2
   ...
   kommando_n
}

Sie geben nach einem frei wählbaren Funktionsnamen runde Klammern an. Die nun folgenden Kommandos, welche diese Funktion ausführen soll, werden zwischen geschweifte Klammern gesetzt. Folgende Aspekte müssen Sie allerdings bei der Definition einer Funktion beachten:

gp  funktions_name und die Klammerung () (bzw. das gleich anschließend gezeigte Schlüsselwort function und funktions_name) müssen in einer Zeile stehen.
gp  Vor der sich öffnenden geschweiften Klammer »{« muss sich mindestens ein Leerzeichen oder ein Newline-Zeichen befinden.
gp  Vor einer sich schließenden geschweiften Klammer »}« muss sich entweder ein Semikolon oder ein Newline-Zeichen befinden.

Somit lässt sich eine Funktion wie folgt auch als Einzeiler definieren:

funktions_name() { kommando1 ; kommando2 ; ... ; kommando_n ; }

Rheinwerk Computing

6.1.1 Definition (Bash und Korn-Shell only)  downtop

In der Bash und der Korn-Shell steht Ihnen hierzu mit dem Schlüsselwort function noch die folgende Syntax zur Verfügung, um eine Funktion zu definieren:

function funktions_name {
   kommando1
   kommando2
   ...
   kommando_n
}

Im Unterschied zur herkömmlichen Syntax, die für alle Shells gilt, fallen beim Schlüsselwort function die runden Klammern hinter dem Funktionsnamen weg.


Rheinwerk Computing

6.1.2 Funktionsaufruf  downtop

Funktionen müssen logischerweise immer vor dem ersten Aufruf definiert sein, da ein Script ja auch von oben nach unten, Zeile für Zeile, abgearbeitet wird. Daher befindet sich die Definition einer Funktion immer am Anfang des Scripts bzw. vor dem Hauptprogramm.

Wird im Hauptprogramm die Funktion aufgerufen, was durch die Notierung des Funktionsnamens geschieht, werden die einzelnen Befehle im Funktionsblock ausgeführt.

# Demonstriert einen einfachen Funktionsaufruf
# Name: afunc1
# Die Funktion hallo
hallo() {
   echo "In der Funktion hallo()"
}
# Hier beginnt das Hauptprogramm
echo "Vor der Ausführung der Funktion ..."
# Jetzt wird die Funktion aufgerufen
hallo
# Nach einem Funktionsaufruf
echo "Weiter gehts im Hauptprogramm"

Das Script bei der Ausführung:

you@host > ./afunc1
Vor der Ausführung der Funktion ...
In der Funktion hallo()
Weiter gehts im Hauptprogramm

Die Shell-Funktion wird von der laufenden Shell ausgeführt und ist somit auch Bestandteil des aktuellen Prozesses (es wird keine Subshell verwendet). Im Unterschied zu vielen anderen Programmiersprachen ist der Zugriff auf die Variablen innerhalb eines Shellscripts auch in Funktionen möglich, obwohl sie hier nicht definiert wurden. Dies bedeutet auch: Wird eine Variable in der Funktion modifiziert, gilt diese Veränderung ebenso für das Hauptprogramm. Das folgende Script demonstriert dies:

# Demonstriert einen einfachen Funktionsaufruf
# Name: afunc2
# Die Funktion print_var
print_var() {
   echo $var             # test
   var=ein_neuer_Test    # var bekommt neuen Wert
}
var=test
echo $var   # test
print_var   # Funktionsaufruf
echo $var   # ein_neuer_Test

Das Script bei der Ausführung:

you@host > ./afunc2
test
test
ein_neuer_Test

Weil eine Shell-Funktion dem eigenen Prozess zugeteilt ist, können Sie diese genauso wie eine Variable mit unset wieder entfernen.

# Demonstriert einen einfachen Funktionsaufruf
# Name: afunc3
# Die Funktion print_var
print_var() {
   echo $var             # test
   var=ein_neuer_Test    # var bekommt neuen Wert
}
var=test
echo $var        # test
print_var        # Funktionsaufruf
echo $var        # ein_neuer_Test
unset print_var  # Funktion löschen
print_var        # Fehler!!!

Das Script bei der Ausführung:

you@host > ./afunc3
test
test
ein_neuer_Test
./afunc1: line 16: print_var: command not found

Hinweis   Bei Korn-Shell und Bash ist mit unset zum Löschen der Funktionen die Option -f erforderlich, weil es hier erlaubt ist, dass Funktionen und Variablen denselben Namen haben dürfen. Existiert hier eine Variable mit dem gleichen Namen, wird die Variable gelöscht und nicht – wie vielleicht beabsichtigt – die Funktion. Die Bourne-Shell hingegen erlaubt keine gleichnamigen Bezeichnungen von Funktionen und Variablen.



Rheinwerk Computing

6.1.3 Funktionen exportieren  downtop

Wenn Funktionen wie einfache Variablen mit unset wieder gelöscht werden können, werden Sie sich sicherlich fragen, ob man Funktionen auch in Subprozesse exportieren kann. Allgemein gibt es keine Möglichkeit, Shell-Funktionen zu exportieren. Ausnahme ist wieder die Bash: Hier können Sie mittels export –f funktions_name eine Funktion zum Export freigeben.

Bourne-Shell und Korn-Shell hingegen können keine Funktionen exportieren. Hierbei steht Ihnen nur der Umweg über den Punkteoperator mittels

. functions_name

zur Verfügung. Dabei muss die Funktion in einer Datei geschrieben und mittels . functions_name (oder auch source functions_name) eingelesen werden. Ein Beispiel:

# Name: afunc_ex
echo "Rufe eine externe Funktion auf ..."
. funktionen
echo "... ich bin fertig"

Im Beispiel wird die Datei »funktionen« in das Script (keiner Subshell) eingelesen und ausgeführt. Die Datei und Funktion sieht wie folgt aus:

# Name: funktionen
# Funktion localtest
afunction() {
   echo "Ich bin eine Funktion"
}

Das Script bei der Ausführung:

you@host > ./afunc_ex
Rufe eine externe Funktion auf ...
... ich bin fertig

Hinweis   Auch wenn mit Bourne- und Korn-Shell keine echten Exporte umsetzbar sind, so stehen den Subshells, welche durch eine Kopie des Eltern-Prozesses entstehen, auch die Funktionen des Elternprozesses zur Verfügung und werden mitkopiert. Eine solche Subshell wird erstellt mit `...`, (...) und einem direkten Scriptaufruf. Natürlich setzt ein direkter Scriptaufruf voraus, dass keine Shell vorangestellt wird (bspw. ksh scriptname) und dass sich auch in der ersten Zeile nichts bezogen auf eine andere Shell befindet (bspw. #!/bin/ksh). Bei der Korn-Shell müssen Sie außerdem noch typeset -fx functions_name angeben, damit den Subshells auch hier die aktuellen Funktionen des Eltern-Prozesses zur Verfügung stehen. Denn dies geschieht im Gegensatz zur Bourne-Shell bei der Korn-Shell nicht automatisch.


Funktionsbibliotheken

Der Vorgang, der Ihnen eben mit dem Punkteoperator demonstriert wurde, wird ebenso verwendet, wenn Sie eine Funktionsbibliothek erstellen wollen, in der sich immer wiederkehrende kleine Routinen ansammeln. Damit können Sie mit Ihrem Script die gewünschte Bibliotheksdatei einlesen und so auf alle darin enthaltenen Funktionen zugreifen. Der Aufruf erfolgt dabei aus Ihrem Script mit (der Bibliotheksname sei stringroutinen.bib):

. stringroutinen.bib

Hier wird natürlich davon ausgegangen, dass sich die Script-Bibliotheksdatei im selben Verzeichnis wie das laufende Script befindet. Nach diesem Aufruf im Script stehen Ihnen die Funktionen von stringroutine.bib zur Verfügung.


Hinweis   Wenn Sie jetzt motiviert sind, eigene Bibliotheken zu schreiben, so bedenken Sie bitte den Umfang einer solchen Datei. Schließlich muss die komplette Bibliotheksdatei eingelesen werden, nur um meistens ein paar darin enthaltene Funktionen auszuführen. Daher kann es manchmal ratsam sein, eher über Copy & Paste die nötigen Funktionen in das aktuelle Script einzufügen – was allerdings dann wiederum den Nachteil hat, dass Änderungen an der Funktion an mehreren Orten vorgenommen werden müssen.



Rheinwerk Computing

6.1.4 Aufrufreihenfolge  downtop

Sollten Sie einmal aus Versehen oder mit Absicht eine Funktion schreiben, zu der es ebenfalls ein internes Shell-Kommando oder gar ein externes Kommando gibt, richtet sich die Shell nach folgender Aufrufreihenfolge: Existiert eine selbst geschriebene Shell-Funktion mit entsprechenden, aufgerufenen Namen, wird sie ausgeführt. Gibt es keine Shell-Funktion, wird das interne Shell-Kommando (Builtin) bevorzugt. Gibt es weder eine Shell-Funktion noch ein internes Shell-Kommando, wird nach einem externen Kommando in den Suchpfaden (PATH) gesucht. Also nochmals die Reihenfolge:

1. Shell-Funktion
       
2. Internes Shell-Kommando
       
3. Externes Kommando (in PATH)
Rheinwerk Computing

6.1.5 Who is who  downtop

Wissen Sie nicht genau, um was es sich bei einem Kommando denn nun handelt, können Sie dies mit type abfragen, beispielsweise:

you@host > hallo() {
> echo "Hallo"
> }
you@host > type hallo
hallo is a function
hallo ()
{
    echo "Hallo"
}
you@host > type echo
echo is a shell builtin
you@host > type ls
ls is aliased to `/bin/ls $LS_OPTIONS`
you@host > type ps
ps is hashed (/bin/ps)
you@host > type type
type is a shell builtin

Rheinwerk Computing

6.1.6 Aufruf selbst bestimmen  downtop

Haben Sie zum Beispiel eine Funktion, von der Sie eine Shell-Funktion, ein internes Shell-Kommando und ein externes Kommando auf Ihrem Rechner kennen, so können Sie auch hierbei selbst bestimmen, was ausgeführt werden soll. Einfachstes Beispiel ist echo, von dem sowohl ein Shell-internes als auch ein externes Kommando existiert. Schreiben Sie bspw. noch eine eigene echo-Funktion, dann hätten Sie hierbei drei verschiedene Varianten auf Ihrem System zur Verfügung.

Der Aufrufreihenfolge nach wird ja die selbst geschriebene Shell-Funktion bevorzugt, sodass Sie diese weiterhin mit dem einfachen Aufruf ausführen können. Wollen Sie allerdings jetzt das interne Shell-Kommando (Builtin) verwenden, müssen Sie dies der Shell mit dem Schlüsselwort builtin mitteilen, damit nicht die Shell-Funktion ausgeführt wird:

you@host > builtin echo "Hallo Welt"
Hallo Welt

Wollen Sie hingegen das externe Kommando echo aufrufen, müssen Sie den absoluten Pfad zu echo verwenden:

you@host > /bin/echo "Hallo Welt"
Hallo Welt

Warum sollten Sie bei echo das externe Kommando verwenden, wo beide doch dieselbe Funktionalität haben? Versuchen Sie einmal, das interne Kommando mit ––help um Hilfe zu bitten, versuchen Sie es dann beim externen.


Rheinwerk Computing

6.1.7 Funktionen auflisten  toptop

Wollen Sie auflisten, welche Funktionen in der laufenden Shell zurzeit definiert sind, können Sie sich mit set oder typeset einen Überblick verschaffen (siehe Tabelle 6.1).


Tabelle 6.1   Auflisten definierter Funktionen

Kommando Shells Bedeutung
set sh, bash Gibt alle Variablen und Funktionen mit kompletter Definition aus
typeset –f ksh, bash Listet alle Funktionen mit kompletter Definition auf
typeset –F ksh, bash Listet alle Funktionen ohne Definition auf



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.


[Rheinwerk Computing]

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