5.7 Error handling und debugging

Inhalt

Error handling

Beim Schreiben von Code ist es sehr wichtig, mögliche Fehler abzufangen und entsprechend darauf zu reagieren. In Bash gestaltet sich das error handling relativ rudimentär. Hier muss man mit if/else Anweisungen jeweils prüfen, ob ein ausgeführter Befehl erfolgreich war:

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

if result=$(rm /tmp/non-existent 2>&1) ; then
  echo "file removed"
else
  echo "error removing file: ${result}"
  # fix error
fi

Resultat

1
2
[user@host]$ /tmp/script.sh
error removing file: rm: cannot remove '/tmp/non-existent': No such file or directory

Mit einer if/else Anweisung können zwar Fehler abgefangen werden, allerdings lassen sich die verschiedenen Fehler nicht unterscheiden. Python bietet hier deutlich mehr Möglichkeiten. In Python lassen sich Fehler mit einem try/except Block abfangen:

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

import os

try:
    os.remove("/tmp/non-existent")
except FileNotFoundError:
    print("could not remove file: file does not exist")
except PermissionError:
    print("could not remove file: permission denied")
except:
    print("could not remove file: unhandled error")

Der Anweisungsblock unter dem try wird immer ausgeführt. Sollte innerhalb dieses Blockes ein Fehler (eine exception) auftreten, wird der zur exception passende Block ausgeführt. Im Beispiel oben versuchen wir eine Datei /tmp/non-existent zu entfernen und haben insgesamt drei exception Blöcke, um folgende Fehler abzudecken:

  • except FileNotFoundError: dieser Block wird ausgeführt, wenn die zu löschende Datei nicht existiert
  • except PermissionError: dieser Block wird ausgeführt, wenn der User keine Schreibrechte auf die zu löschende Datei hat
  • except: dieser Block deckt alle anderen Fehler ab

In unserem Beispiel geben wir jeweils nur einen kurzen Text aus. Natürlich lassen sich in einem except Block aber auch komplexere Aufgaben erledigen. Wie du siehst, bietet Python in Sachen Fehlerbehandlung viel mehr Möglichkeiten als Bash.

Debugging

Bash

Bash Scripts lassen sich verhältnismässig einfach troubleshooten, da die Befehle in einem solchen Script 1:1 interaktiv in einer Bash abgesetzt werden können. Du kannst also Teile des Scripts ausführen und jeweils den Inhalt der einzelnen Variablen mit einem echo Kommando ausgeben lassen. Weiter lässt sich Bash über das set Kommando so konfigurieren, dass sämtlich Befehle vor deren Ausführung ausgegeben werden: set -x.

Du kannst diesen Befehl auch bereits von Anfang in dein Script integrieren und über eine Umgebungsvariable steuern:

1
2
3
4
5
6
7
8
#!/bin/env bash
[[ -v TRACE ]] && set -x

if result=$(rm /tmp/non-existent 2>&1) ; then
    echo "file removed"
else
    echo "error removing file: ${result}"
fi
1
2
3
4
5
[user@host}$ TRACE=true /tmp/test.sh
++ rm /tmp/non-existent
+ result='rm: cannot remove '\''/tmp/non-existent'\'': No such file or directory'
+ echo 'error removing file: rm: cannot remove '\''/tmp/non-existent'\'': No such file or directory'
error removing file: rm: cannot remove '/tmp/non-existent': No such file or directory

Python

Auch Python Scripte lassen sich relativ einfach debuggen. Meist hilft die jeweilige Fehlermeldung und eine kurze Suche mit der Suchmaschine deiner Wahl bereits weiter. Zusätzlich bieten viele IDEs Debugging Tools für Python an, mit welchen du z.B. den Wert einer Variable während der Ausführung einsehen kannst. Eine Anleitung für visual studio code findest du z.B. hier: https://code.visualstudio.com/docs/python/debugging

Lint

Lint bezeichnet ein Werkzeug zur Code-Analyse, bei welchem dein Code auf gängige Fehler und best practices untersucht wird.

Bash

Für Bash kannst du z.B. shellcheck verwenden, welches sich über pip installieren lässt: pip install shellcheck-py. Anschliessend kannst du dein Script über den folgenden Befehl linten lassen:

1
2
3
4
5
6
7
user@host]$ shellcheck /path/to/your/script.sh

In /path/to/your/script.sh line 1:

^-- SC2148 (error): Tips depend on target shell and yours is unknown. Add a shebang or a 'shell' directive.

For more information:

In diesem Beispiel bemängelt shellcheck, dass wir vergessen haben, den shebang zu setzen.

Python

Das am häufigsten eingesetzt lint Tool für Python ist pylint auch dieses lässt sich über pip installieren: pip install pylint. Die Anwendung von pylint ist ebenfalls sehr einfach:

user@host]$ pylint /path/to/your/script.py
************* Module test
/path/to/your/script.py:1:0: C0114: Missing module docstring (missing-module-docstring)

------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)

In diesem Fall bemängelt pylint, dass wir vergessen haben, einen module docstring zu erstellen. Mit der jeweiligen Fehlernummer (in diesem Fall C0114) findet in der Dokumentation von pylint eine genaue Beschreibung sowie Ansätze, wie das Problem gelöst werden kann: https://pylint.readthedocs.io/en/latest/user_guide/messages/convention/missing-module-docstring.html

Zuletzt geändert March 17, 2023: fix typos (81c8777)