Funktionen dienen in einem Script dazu, sich wiederholende Abläufe mehrerer Kommandos zu bündeln und sparen somit Zeit und Tipparbeit. Nichts hasst ein Informatiker mehr, als sich wiederholen zu müssen. 😉

Funktionen
Funktionen findest du in nahezu jeder Programmiersprache. In objektorientierten Sprache heißen sie dann meist Methoden. Sie haben alle denselben Sinn: Ein Stück Programmcode zur mehrfachen Verwendung zu kapseln. Am Einfachsten demonstriere ich das mal an diesem Script:
#! /usr/bin/bash
# File: mult-echo.sh
echo "Hallo 1"
echo "-------"
echo "Hallo 1"
echo "-------"
echo "Hallo 1"
echo "-------"
echo "Hallo 1"
echo "-------"
Es gibt viermal den Text „Hallo 1“ aus, gefolgt von einer horizontalen Linie in der nächsten Zeile. Dies ist nicht nur unpraktisch sondern macht das Script auch hässlich.

An den Wiederholungen erkennst du schon, dass die beiden echo
in einer Funktion besser aufhoben wären. Dorthin verschieben wir sie direkt mal:
#! /usr/bin/bash
# File: simple-func.sh
function hallo() {
echo "Hallo 1"
echo "-------"
}
hallo
hallo
hallo
hallo
Eine Funktion wird immer mit dem Schlüsselwort function
deklariert. Gefolgt von ihrem Namen (hier hallo
). Die Deklaration wir durch das Klammerpaar ()
beendet. Danach folgt der Funktionskörper, der in einem Paar geschwungenen Klammern {}
den Code aufnimmt.

Im Script können wir jetzt die Funktion beliebig oft aufrufen.
Noch eleganter wird es, wenn wir den Funktionsaufruf in eine Schleife packen:
#! /usr/bin/bash
# File: loop-func.sh
function hallo() {
echo "Hallo 1"
echo "-------"
}
count=1
while [ ${count} -le 4 ]; do
hallo
count=$((${count} + 1))
done

Das ist die simpelste Möglichkeit, Funktionen einzusetzen. Als nächstes wollen wir die Hallos hochzählen.
Parameter
An eine Funktion kannst du auch Parameter übergeben. In anderen Programmiersprachen musst du diese noch deklarieren. In der bash läuft das etwas anders.
#! /usr/bin/bash
# File: param-func.sh
function hallo() {
echo "Hallo ${1}"
}
count=1
while [ ${count} -le 4 ]; do
hallo "${count}"
count=$((${count} + 1))
done
Den Schleifenzähler übergeben wir jetzt mit hallo "${count}"
an die Funktion. Wie schon bei den Parametern für ein Script, kann dieser dann in der Variable ${1}
abgefragt werden. ${0}
enthält in der Funktion den Funktionsnamen!
Du erkennst durch das Mechanismus vielleicht selbst, dass eine Funktion wie ein im Script definiertes Unterscript wirkt.

Rückgabewert
Häufig werden in Funktionen Werte ermittelt, diese müssen wir wieder an die aufrufende Stelle zurückgeben können.
function square() {
return $(( ${1} * ${1} ))
}
square "2"
echo "Quadrat von 2 ist ${?}"
square "4"
echo "Quadrat von 4 ist ${?}"
square "3"
echo "Quadrat von 3 ist ${?}"
Wir haben hier eine Funktion, die die Quadratzahl des übergebenen Werts berechnet. Dazu wird der Parameter ${1} einfach mit sich selbst multipliziert. Sie gibt das berechnete Ergebnis mit return
zurück. Danach kann es in der Variable ${?} ausgelesen werden.
return
ist für eine Funktion das, was exit für das gesamte Script ist, es liefert einen Zahlenwert zwischen 0 und 255 als Ergebnis des erfolgreichen Durchlaufs der Funktion. Ich erweitere das Script noch um die Berechnung des Quadrats von 32
square "32"
echo "Quadrat von 32 ist ${?}"
Dabei erhalte ich dieses Ergebnis

Statt 1024 als Ergebnis für 32² erhalten wir hier 0. Dies liegt daran, dass der Wertebereich der möglichen Rückgabewerte von return
überschritten wurde.
Das ist natürlich nicht tragbar und wir brauchen eine Lösung dafür. Diese finden wir im echo
Kommando.
Rückgabewert mit echo
echo definiert sozusagen die Ausgabe der Funktion. In diesem Beispiel siehst du, was passiert.
#! /usr/bin/bash
# File: return-value.sh
function square() {
echo $(( ${1} * ${1} ))
}
square "2"
square "4"
square "3"
square "32"
Beim Durchlauf werden alle Ergebnisse im Terminal ausgegeben.

Nun ist aber meistens so, dass du das Ergebnis nicht im Terminal haben möchtest, sondern weiterverarbeitet werden soll. Dazu kannst du den Funktionsaufruf einfach mit einer Variablenzuweisung verbinden bspw. s2=$(square "2")
. So kannst du Berechnung und Weiterverarbeitung voneinander trennen:
#! /usr/bin/bash
# File: return-value-echo2.sh
function square() {
echo $(( ${1} * ${1} ))
}
s2=$(square "2")
s4=$(square "4")
s3=$(square "3")
s32=$(square "32")
echo "Das Quadrat von 2 ist ${s2}"
echo "Das Quadrat von 4 ist ${s4}"
echo "Das Quadrat von 3 ist ${s3}"
echo "Das Quadrat von 32 ist ${s32}"
Die Ausgabe ähnelt der von oben, allerdings das Ergebnis für 32² jetzt korrekt.

Gültigkeitsbereich einer Variable
Auch wenn dieser Post schon wieder umfangreicher geworden ist, als ursprünglich geplant, möchte ich zum Abschluss noch auf den sog. Scope von Variablen, also deren Gültigkeitsbereich eingehen. Auf alle Variablen, die vom Hauptprogramm definiert werden, kann eine Funktion auch zugreifen, eine Änderung des Werts innerhalb der Funktion betrifft dann auch das Hauptprogramm. So etwas solltest du möglichst vermeiden, es macht die Fehlersuche unnötig kompliziert.
Andererseits sind alle Variablen, die innerhalb einer Funktion definiert werden, auch global und können vom Hauptprogramm ausgelesen werden. Diese belegen nach Ende der Funktion weiterhin Speicher, den du vermutlich besser verwenden kannst. Mit dem Schlüsselwort local
kannst du in der Funktion Variablen so deklarieren, dass sie im Gültigkeitsbereich der Funktion liegen. Nach dem Ende der Funktion werden sie automatisch abgeräumt und der Speicher freigegeben.
#!/usr/bin/bash
# File: scope/scope.sh
# Globale Variable
global_var="Ich bin global"
# Funktion mit lokaler Variable
funktion_mit_lokaler_var() {
local local_var="Ich bin lokal"
var_ohne_local="Ich bin lokal ohne local"
global_var="Ich wurde in der Funktion verändert"
echo "Innerhalb der Funktion:"
echo "Globale Variable: ${global_var}"
echo "Lokale Variable: ${local_var}"
}
# Hauptskript
echo "Vor Funktionsaufruf:"
echo "Globale Variable: ${global_var}"
# Funktionsaufruf
funktion_mit_lokaler_var
# Nach Funktionsaufruf
echo "Nach Funktionsaufruf:"
echo "Globale Variable: ${global_var}"
echo "var_ohne_local: ${var_ohne_local}"
# Versuch, auf die lokale Variable zuzugreifen (dies wird fehlschlagen)
echo "Versuch, auf die lokale Variable außerhalb der Funktion zuzugreifen:"
echo "Lokale Variable: ${local_var}"
Dieses Beispielprogramm zeigt dir, wie die verschiedenen Scope reagieren.
