Funktionen E-Mail
Geschrieben von: tpm   

In frühen Programmiersprachen wurden wiederkehrende Programmabläufe durch Sprunganweisungen realisiert. Das hatte zur Folge, dass der Programmcode unübersichtlich wurde und es dadurch zu vermehrten Fehlern kam. Dieses Verfahren wurde weitestgehend durch die Aufteilung in Programmteile ersetzt.

 

Diese Programmteile werden durch Funktionen realisiert. Ihr Hauptvorteil besteht darin, dass sie die Übersichtlichkeit eines Scripts enorm verbessern. Zudem können Funktionen immer wieder in anderen Scripten verwendet werden. Dies spart bei komplexeren Funktionen enorm viel Arbeitszeit.

Auf der anderen Seite ist es beim Shell Scripting nicht immer ratsam jeden Arbeitsablauf in Funktionen auszulagern. Programmabläufe können sich zwar ähneln, haben aber im Kontext mit dem gesamten Programm oder auch nur einem Teil des Programms eine völlig andere Bedeutung. Letztendlich erfordert das richtige Maß für die Verwendung von Funktionen nicht zuletzt Erfahrung. Diese kann durch den Beitrag leider nicht vermittelt werden.

 

Das Konstrukt einer Funktion stellt sich im Wesentlichen wie folgt dar:

 

example
Funktionsname ()
{
Aktion
}

 

Der Aufruf der Funktion erfolgt an beliebiger Stelle im Script, jedoch nach der Angabe der Funktion selbst, einfach über den Funktionsnamen. Dieser ist wieder ein frei wählbarer Bezeichner. Die Notation entspricht der von Variablen, wobei Funktionsnamen immer klein geschrieben werden sollten.

Zur Verdeutlichung des Aufbaus und der Arbeitsweise soll nun folgendes praktisches Beispiel dienen. Ein Script, dass auf verschiedene übergebene Parameter beim Programmaufruf entsprechend reagieren soll.

 

input
#!/bin/bash

# Scriptname: myScript

oFunktion ()
{
echo 'Option -o wurde gewählt. Arbeite Code ab...'
# Hier stehen nun mehrere Zeilen Code...
}

pFunktion ()
{
echo 'Option -p wurde gewählt. Arbeite Code ab...'
# Hier stehen nun mehrere Zeilen Code...
}

mFunktion ()
{
echo 'Option -m wurde gewählt. Arbeite Code ab...'
# Hier stehen nun mehrere Zeilen Code...
}

for element
do
case $element in
-o) oFunktion ;;
-p) pFunktion ;;
-m) mFunktion ;;
*) echo 'Es wurden keine passenden Parameter übergeben'
esac
done

 

Wird dieses Script nun mit Parametern gestartet, wie beispielsweise ./myScript -o -p -m, dann werden die Parameter geprüft und die entsprechende Funktion über die case-Abfrage aufgerufen. Anschließend wird der Programmcode innerhalb der Funktion abgearbeitet und nach Beendigung zum case-Konstrukt zurück gesprungen. Bei dem oben angegebenen Programmaufruf führt das Script zu folgender Ausgabe...

 

input
Option -o wurde übergeben. Arbeite Code ab...
Option -p wurde übergeben. Arbeite Code ab...
Option -m wurde übergeben. Arbeite Code ab...

 

Stellt man sich nun vor, dass innerhalb der Funktionen nun wirklich eine Menge Programmcode vorhanden wäre (was in dem Beispiel durch die Kommentare symbolisiert werden soll), dann wird einem deutlich, wie unübersichtlich das Script ohne Funktionen wäre. Dann nämlich müsste der gesamte Code innerhalb des case-Konstrukts untergebracht werden.

Und nochmal zum Festhalten: Funktionen werden nicht automatisch abgearbeitet. Sie müssen aufgerufen werden! Das Script beginnt also eigentlich erst mit der for-Schleife. Die Funktionen davor zeigen dem Script nur, dass es sie gibt und sie aufgerufen werden können, wenn nötig.

 

Eine weitere nützliche Möglichkeit bei Funktionen ist das übergeben von Parametern. Man im Vorfeld zwar was in der Funktion gemacht werden soll, aber oft nicht mit welchen Werten. Ist die Anzahl der möglichen Parameter gering, könnte man zu Not für jeden Fall eine eigene Funktion schreiben. Nicht sehr hübsch, aber möglich. Bei einer unvorhersehbaren Anzahl an Parametern hingegen wäre dieser Weg nahezu unmöglich. Hier hat die Parameterübergabe ihre Stärken.

Um den Nutzen der Parameterübergabe praktisch zu verdeutlichen, soll folgendes Sript dienen, welches die Fläche eines Kreises anhand des eingegebenen Radius berechnet.

 

input
#!/bin/bash

flaeche()
{
temp=`echo "$1 * $1" | bc`
ergebnis=`echo "3.141 * $temp" | bc`
echo "Die Fläche beträgt in etwa $ergebnis FE"
echo "Bitte RETURN drücken..."
read
}

eingabe=""

while [ "$eingabe" != "q" ]
do
clear
echo "Bitte geben Sie den Radius ein oder drücken q zum Beenden."
read eingabe

if [ "$eingabe" != "q" ]
then
flaeche "$eingabe" # Funktionsaufruf mit Parameterübergabe
fi
done

 

Solange also nicht q als Eingabe getätigt wird, sondern eine Zahl eingegeben wird, wird der eingegebene Wert als Parameter über den Funktionsaufruf flaeche "$eingabe" an die Funktion flaeche() übergeben. Die Abfrage des Parameters geschieht mit der Systemvariablen $1, welche bekanntermaßen ebenfalls bei der Parameterübergabe beim Programmaufruf verwendet wird. Innerhalb von Funktionen jedoch repräsentieren die Systemvariablen ( $1, $2, $3, ... ) ausschließlich die übergebenen Parameter der Funktion. Sie beeinflussen sich also nicht gegenseitig mit den übergebenen Parametern vom Programmstart.

 

Damit aber noch nicht genug. Eine Funktion kann nicht nur Parameter übernehmen, sondern auch einen Wert zurückliefern. Dabei beschränkt sich der Rückgabewert allerdings auf eine natürliche Zahl inklusive der 0. Ein Rückgabewert ist immer dann nützlich, wenn ein Programm auf die erfolgreiche oder nicht erfolgreiche Durchführung einer Funktion entsprechend reagieren soll.

Dazu wird das obige Script nun dahingehend verändert, dass es nicht mehr ein Ergebnis in FE innerhalb der Funktion ausgeben soll, sondern einfach prüft, ob das Ergebnis größer oder kleiner gleich 500 FE ist und diese Erkenntnis abschließend ausgibt.

 

input
#!/bin/bash

pruefe()
{
temp=`echo "$1 * $1" | bc` #------------------------
ergebnis=`echo "3.141 * $temp" | bc` # Berechnungsblock
ergebnis=`echo "$ergebnis <= 500" | bc` #------------------------
return $ergebnis # Liefert 1 oder 0 zurück
}

eingabe=""

while [ "$eingabe" != "q" ]
do
clear
echo "Bitte geben Sie den Radius ein."
read eingabe

if [ "$eingabe" != "q" ]
then
pruefe "$eingabe"

if [ $? -eq 1 ]
then
echo "Die Fläche ist kleiner oder gleich 500 FE."
else
echo "Die Fläche ist größer 500FE."
fi
echo "Bitte RETURN drücken..."
read
fi
done

 

Die Funktion gibt also, abhängig davon ob das Ergebnis kleiner gleich oder größer als 500 ist den Wert 1 oder 0 zurück. Die Systemvariable zur Abfrage des Rückgabewerts ist $?. Dabei gelten die gleichen Regeln wie für die Systemvariablen für Parameterabfragen. Sie ist also innerhalb des Programms ausschließlich für dieses zuständig. Rückgabewerte von parallelen systemweiten Prozessen werden hier nicht erfasst.

 

Anmerkung: Die Bash eignet sich eigentlich weniger für komplexe mathematische Berechnungen. Sie sind zwar möglich, erfordern aber oft umständlichen Programmcode (siehe obiges Beispiel für die einfache Flächenberechnung) und sind aus rechnerischer Sicht nicht effizient. Letzteres macht sich zugegebenermaßen, bei einfachen Berechnungen, in der Praxis kaum bemerkbar.

 

Zuletzt aktualisiert am Donnerstag, den 29. Oktober 2009 um 13:41 Uhr