bash Scripting: Funktionen Tutorial Teil 16

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. 😉

Dr. Dirk Colbry, Michigan State
Gnu-bash-logoCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
1Einführung
2Der bash Prompt
3key bindings
4Der Startvorgang
5Environment Variablen
6builtin commands
7Arbeiten mit Dateien
8nano
9bash Scripting
10Variablen
11Verzweigungen (if)
12Schleifen
13Kommandozeilenparameter
14exit Codes bash Tutorial Teil 14
15von der Idee zum Script
16grep

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.

Ausgabe von mult-echo.sh
Olli Graf - raspithek.de
mult-echoCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ausgabe von mult-echo.sh

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.

Ausgabe von simple-func.sh
Olli Graf - raspithek.de
simple-funcCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ausgabe von simple-func.sh

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
Ausgabe von loop-func.sh
Olli Graf - raspithek.de
loop-funcCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ausgabe von loop-func.sh

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.

Ausgabe von param-func.sh
Olli Graf - raspithek.de
param-funcCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ausgabe von param-func.sh

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

Ausgabe von return-value-return.sh
Für das Quadrat von 32 wird 0 zurückgeliefert.
Olli Graf - raspithek.de
return-value-returnCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ausgabe von return-value-return.sh

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.

Ausgabe von return-value-echo.sh
Olli Graf - raspithek.de
return-value-echoCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ausgabe von return-value-echo.sh

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.

Ausgabe von return-value-echo2.sh
Olli Graf - raspithek.de
return-value-echo2Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ausgabe von return-value-echo2.sh

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.

Ausgabe von scope.sh
Olli Graf - raspithek.de
scopeCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Ausgabe von scope.sh

Schreibe einen Kommentar

Creative Commons License
Except where otherwise noted, the content on this site is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Olli Graf - raspithek.de
WordPress Cookie Hinweis von Real Cookie Banner