5.5 Funktionen

Inhalt

Was sind Funktionen

In einem Script oder Programm kommt es oft vor, dass ein Teil des Codes mehrmals ausgeführt werden soll. Nehmen wir an, du schreibst ein Script, welches ein Backup deiner Dateien erstellt. Du möchtest, dass das Script am Anfang ein E-Mail schickt und dich informiert, dass das Backup gestartet wurde. Sobald das Backup erstellt wurde, möchtest du ein zweites E-Mail mit dem Resultat (z.B. Anzahl gesicherte Dateien) erhalten. Der Code, welcher das E-Mail generiert und verschickt, müsste in deinem Programm also einmal am Start und einmal am Ende des Scripts vorkommen. Dadurch wird dein Programm unnötig lang und Änderungen müssen jeweils an mehreren Stellen eingepflegt werden. Hier helfen Funktionen. In Funktionen wird ein Teil deines Codes abgekapselt.

Syntax

Bash

1
2
3
name_der_funktion () {
    #Anweisungsblock
}

Python

1
2
3
4
5
6
7
8
def name_der_funktion(parameter1, parameter2):
    """Dieser Text ist der docstring der Funktion name_der_funktion
    Wie du bereits im Kapitel 1 dieses Labs gelernt hast, dienen Docstrings dazu,
    die Funktion deines Codes zu beschreiben. Du solltest daher zusätzlich zum
    Module Docstring (beschreibt die Funktion/den Zweck des Scripts) auch für jede Funktion
    einen Function Docstring schreiben, welcher die jeweilige Funktion beschreibt.
    """
    # Anweisungsblock

Sowohl in Bash als auch in Python sind die Parameter optional. In Bash können wir (analog zum im Lab 3 beschriebenen Verhalten) über die Variablen $1 bis $9 auf übergebene Argumente zugreifen. In Python definieren wir die gewünschten Parameter in den Klammern bei der Definition der Funktion. Anschliessend können wir innerhalb dieser Funktion über den Namen des Parameters auf den jeweiligen Wert zugreifen (wie bei einer gewöhnlichen Variable)

Das Definieren einer Funktion führt nicht automatisch zur Ausführung dieses Codes. Du musst also deine Funktionen einerseits definieren und anschliessend über den Namen (optional mit Parametern) aufrufen.

Beispiele

Bash

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#!/bin/env bash


send_mail () { # Definition der Funktion
    # hier wird das E-Mail verschickt
    # $1 = recipient
    # $2 = text
    echo "E-Mail an ${1} erfolgreich verschickt"
}

send_mail "test@puzzle.ch" "Backup gestartet" # Aufruf der Funktion
# hier werden die Daten gesichert
send_mail "test@puzzle.ch" "Backup done!" # Aufruf der Funktion

Python

1
2
3
4
5
6
7
8
9
#!/bin/env python

def send_mail(recipient, text): # Definition der Funktion
    # hier wird das E-Mail verschickt
    print(f"E-Mail an {recipient} erfolgreich verschickt")

send_mail("test@puzzle.ch", "Backup gestartet") # Aufruf der Funktion
# hier werden die Daten gesichert
send_mail("test@puzzle.ch", "Backup done!") # Aufruf der Funktion

Wie du siehst, definieren wir auf Zeile 3 des Scripts die gewünschte Funktion. Auf den Zeilen 7 und 9 rufen wir die Funktion mit den Argumenten test@puzzle.ch und Backup gestartet resp. Backup done! auf.

Variable scope

Im Lab 2 Variablen haben wir gelernt, wie wir Variablen definieren und verwenden. Im Zusammenhang mit Funktionen gibt es bei Variablen etwas zu beachten. Grundsätzlich existiert eine Variable immer in einem bestimmten Scope. Bis anhin haben wir immer globale Variablen verwendet. Globale Variablen sind Variablen, welche im gesamten Script verwendet werden können (also auch in beliebigen Funktionen). Es gibt jedoch auch lokale Variablen, welche jeweils nur innerhalb einer bestimmten Funktion existieren. Wenn wir in Python innerhalb einer Funktion eine neue Variable deklarieren, existiert diese Variable auch nur innerhalb dieser Funktion. Versucht man, ausserhalb der Funktion auf die Variable zuzugreifen, resultiert das in einem Fehler:

1
2
3
4
5
6
7
8
def my_function():
    print(global_var)
    local_var = "I am local"

global_var = "I am global"

my_function()
print(local_var)

Resultat

1
2
3
4
5
6
I am global
Traceback (most recent call last):
  File "/tmp/test.py", line 8, in <module>
    print(local_var)
          ^^^^^^^^^
NameError: name 'local_var' is not defined. Did you mean: 'global_var'?

Wie du siehst, kann die Funktion my_function() zwar auf die Variable zugreifen, welche wir ausserhalb der Funktion definiert haben (global_var), aber im globalen Scope (ausserhalb der Funktion) haben wir keinen Zugriff auf die Variable, welche wir innerhalb der Funktion definiert haben (local_var). In Bash verhält sich das ganze ein wenig anders. In Bash sind grundsätzlich alle Variablen global, es sei denn, man definiert die Variable explizit als lokal:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/env bash
my_function () { # Definition der Funktion
    global_var_2="I am global"
    local local_var="I am local"
    echo $global_var
}

global_var="I am global"
my_function
echo $global_var_2
echo $local_var

Resultat

1
2
3
4
[user@fhost]$ bash ./script.sh
I am global
I am global
 

Beachte: die Variable local_var (I am local) wird nicht ausgegeben.

Return

In Python kann eine Funktion optional einen oder mehrere Werte zurückgeben. Das ist hilfreich, wenn man in einer Funktion Daten verarbeitet und diese anschliessend ausserhalb der Funktion weiterverwenden möchte.

Python

1
2
3
4
5
6
7
8
#!/bin/env python

def add(operand_a, operand_b):
    result = operand_a + operand_b
    return result

calculation = add(1, 2)
print(calculation)

In der Zeile 5 des obigen Scripts verwenden wir das Keyword return, um Python anzuweisen, den Wert der Variable result zurückzugeben. In der Zeile 7 definieren wir eine neue Variable calculation und weisen dieser den Wert zu, den wir von der Funktion add() zurückbekommen.

In Bash können Funktionen keine Werte zurückgeben. Hier ist man daher gezwungen, mit globalen Variablen zu arbeiten oder besser lokale Variablen zu verwenden und den Wert über ein echo auszugeben:

1
2
3
4
5
6
7
8
9
#!/bin/env bash
function add()
{
    local  result=$(( $1 + $2 ))
    echo "${result}"
}

calculation=$(add 1 2)
echo $calculation