5.8 Abschluss

Inhalt

Outro

Nun sind wir am Ende unseres Ausfluges in die Welt der Scripts. Natürlich gibt es noch viele weitere Funktionen und Möglichkeiten, welche du in künftigen Projekten verwenden kannst. Ich möchte dir hierzu noch einige Links mit auf den Weg geben:

  • openbook.rheinwerk-verlag.de In diesem umfangreichen Kurs findest du alles rund um das Thema Bash. Du findest darin weitere interessante Themen wie reguläre Ausdrücke oder auch Tipps und Tricks zur Gestaltung deiner Scripte
  • www.uni-regensburg.de In diesem Tutorial werden nochmals viele Themen rund um Python behandelt. Du findest darin auch eine Einführung in die objektorientierte Programmierung sowie weitere Themen wie numpy.

Beispiele

Wir wollen jetzt das Gelernte der letzten Kapitel anwenden und Beispielscripte schreiben.

  • Schaue dir die Scripts an und versuche zu verstehen, was sie machen
  • Führe die Scripts mit dem Argument -n 60 aus.
  • Prüfe, was passiert, wenn du das Script mit CTRL+C oder dem kill Kommando beendest
  • Teste, was passiert, wenn du dem -n anstelle einer Zahl einen Text übergibst. Wie könnte der Fehler behoben werden?

Bash

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#!/bin/env bash
# Wir beginnen mit dem shebang. Dieser definiert, mit welchem Interpreter das Script ausgeführt werden soll.
# Damit unser Script möglichst auf allen Systemen lauffähig wird, verwenden wir /bin/env und nicht einen hart kodierten Pfad zum Interpreter

# Mit dem set Kommando definieren wir, dass wir unser Script bei der Verwendung von nicht definierten Variablen abbrechen wollen (set -u)
# mit dem `-e` Argument weisen wir Bash an, das Script bei einem fehlgeschlagenen Kommando abzubrechen. Befehle welche Fehler auslösen können,
# fangen wir später mit if/else conditions ab.
# mit dem `-o pipefail` Argument definieren wir, dass wir auch bei mit pipe aneinandergereihten Befehlen (z.B. `grep XY file | cut -d ' ' -f1`)
# auf Fehler achten und das Script im Fehlerfahl beenden wollen
set -euo pipefail

# Als nächstes definieren wir mit `set -x`, dass alle Befehle vor der Ausführung in der Konsole ausgegeben werden sollen
# Das machen wir aber nur, wenn die Umgebungsvariable TRACE gesetzt ist (ansonsten generiert das Script bei jeder Ausführung sehr viel output)
[[ -v TRACE ]] && set -x

# nun definieren wir unsere ersten Variablen
# achte darauf, dass du dich im gesamten Script an eine einheitliche Syntax (camelCase oder snake_case) hältst
my_var="example"
tmp_file=$(mktemp)

# Nun definieren wir eine Funktion, damit beim beenden des Scripts die temporäre Datei gelöscht und ein entsprechender Text zurückgegeben wird
cleanup() {
    echo "entferne die temporäre Datei"
    # da beim Entfernen der temporären Datei ein Fehler auftreten könnte, müssen wir diesen möglichen Fehler abfangen
    if resultat=$(rm "${tmp_file}" 2>&1) ; then
        echo "temporäre Datei wurde entfernt"
    else
        echo "fehler beim Löschen der temporären Datei: ${resultat}"
    fi
    echo "Script wird beendet"
    exit 0
}

# Damit unsere cleanup Funktion beim beenden auch ausgeführt wird, müssen wir diese mit den gewünschten Signalen "verbinden"
trap cleanup SIGTERM SIGINT


# nun definieren wir eine Funktion, welche die Variable my_var mehrfach ausgibt und zusätzlich in die temporäre Datei schreibt
# Wie oft definieren wir mit einem Argument
print_variable() {
    # Um die Variable auszugeben, verwenden wir einen for loop
    for (( index=0; index<=$1; index++ )); do
        echo ${my_var} | tee -a "${tmp_file}"
    done
}

parse_args() {
    # als nächstes parsen wir die Parameter, welche unsere Script übergeben wurden
    # wir erlauben ein einziges Argument `-n` (number)
    while getopts n: flag; do
        case "${flag}" in
            n) number=${OPTARG};;
        esac
    done
}

main() {
    # Wir prüfen zuerst, ob die Variable number definiert ist (https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html)
    if [[ -v number ]]; then
        # Wenn die Variable definiert ist prüfen wir, ob die Zahl grösser oder kleiner als 10 ist
        if [[ number -lt 10 ]]; then
            print_variable ${number} # Funktionsaufruf mit Parameter
        else
            echo "die nummer ist 10 oder grösser"
        fi
    fi

    # Nun fragen wir den User nach einer Zahl
    echo "Gib eine Zahl ein:"
    read wait_time
    if [[ -z ${wait_time} ]]; then
        echo "Du hast nichts eingegeben"
    else
        echo "Das Script wartet nun ${wait_time} Sekunden"
        sleep "${wait_time}"
    fi
}

# Funktionsaufruf zum parsen der Argumente
parse_args
# Hauptfunktion unsers Scripts
main
# Zum schluss führen wir manuell die cleanup() funktion aus, um die temporäre Datei zu löschen
cleanup

Python

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
#!/bin/env python
# Wir beginnen mit dem shebang. Dieser definiert, mit welchem Interpreter das Script ausgeführt werden soll.
# Damit unser Script möglichst auf allen Systemen lauffähig wird, verwenden wir /bin/env und nicht einen hart kodierten Pfad zum Interpreter
""" Dies ist der Module Docstring. Darin beschreiben wir, was unser Script tut """

# nun folgen die imports von weiteren Modulen, welche wir in unserem Script verwenden wollen
import time
import sys
import signal
import getopt
import os
from pathlib import Path

# Nun definieren wir eine Funktion, damit beim beenden des Scripts die temporäre Datei gelöscht und ein entsprechender Text zurückgegeben wird
def cleanup(_signo=None, _stack_frame=None):
    """ Das ist ein function Docstring
    Diese Funktion räumt die temporäre Datei weg und gibt einen kurzen Text aus"""

    print("entferne die temporäre Datei")
    # mit einem try/except Block fangen wir mögliche Fehler ab
    try:
        os.remove(TMP_FILE)
    except FileNotFoundError:
        print("temporäre Datei konnte nicht gelöscht werden: Datei existiert nicht")
    except PermissionError:
        print("temporäre Datei konnte nicht gelöscht werden: Zugriff verweigert")
    except:
        print("temporäre Datei konnte nicht gelöscht werden: ein unbekannter Fehler ist aufgetreten")
    print("Script wird beendet")
    sys.exit(0)


# nun definieren wir eine Funktion, welche die Variable MY_VAR in die temporäre Datei schreibt und zusätzlich die Anzahl Durchläufe auf die Konsole ausgibt.
# Wie oft definieren wir mit einem Argument iterations
def print_variable(iterations):
    """ Diese Funktion schreibt den Wert der Variable  MY_VAR in eine temporäre Datei """
    # Um die Variable auszugeben, verwenden wir einen for loop
    for index in range(iterations):
        print(f"wir befinden uns in der {index}. Wiederholung einer for Schleife")
        with open(TMP_FILE, "a", encoding="utf-8") as file:
            file.write(f"{MY_VAR}\n")
        print(MY_VAR)

def parse_args():
    """ Diese Funktion parsed die Argumente """
    # als nächstes parsen wir die Parameter, welche unsere Script übergeben wurden
    # wir erlauben ein einziges Argument `-n` (number)

    number = None # default Wert des number Arguments
    argv = sys.argv[1:]
    try:
        opts, _args = getopt.getopt(argv, "n:")
        for opt, arg in opts:
            if opt in ['-n']:
                number = int(arg)
    except getopt.GetoptError as error:
        print(error)
        cleanup()
    return number

def startup():
    """ In dieser Funktion bereiten wir den Start unseres Scripts vor """
    # Damit unsere cleanup Funktion beim beenden auch ausgeführt wird, müssen wir diese mit den gewünschten Signalen "verbinden"
    for sig in [signal.SIGTERM, signal.SIGINT]:
        signal.signal(sig, cleanup)
    # temporäre Datei erstellen
    Path(TMP_FILE).touch()

def main():
    """ Das ist die Hauptfunktion unsers Scripts. Sie wird beim start ausgeführt"""
    # Funktionsaufruf ohne Argumente, der return Wert wird der Variable number zugewiesen
    # Diese Variable ist lokal, da sie innerhalb einer Funktion definiert wird
    # Wir können in anderen Funktionen daher nicht auf diese Variable zugreifen, sondern
    # müssen diese als Argument der Funktion übergeben
    number = parse_args()
    # Funktionsaufruf ohne Argumente
    startup()

    # Wir prüfen zuerst, ob die Variable number definiert ist
    if number is not None:
        # Wenn die Variable definiert ist prüfen wir, ob die Zahl grösser oder kleiner als 10 ist
        if number < 10:
            print_variable(number) # Funktionsaufruf mit Argument
        else:
            print("die nummer ist 10 oder grösser")

    # Nun fragen wir den User nach einer Zahl
    wait_time = input("Gib eine Zahl ein: ")
    if not wait_time:
        print("Du hast nichts eingegeben")
    else:
        time.sleep(int(wait_time))
    cleanup()

if __name__ == "__main__":
    # Definition von Variablen
    # Diese Variablen sind global, da sie nicht innerhalb einer Funktion definiert sind
    # achte darauf, dass du dich im gesamten Script an eine einheitliche Syntax (camelCase oder snake_case) hältst
    MY_VAR = "example"
    TMP_FILE = "/tmp/tmpfile"
    main()
Zuletzt geändert March 17, 2023: fix typos (81c8777)