Signale mit trap abfangen – bash Tutorial Teil 25

Wenn der User dein Script mit CTRL-C abbricht, ist ein kontrolliertes Beenden und Aufräumen nicht mehr möglich. Dies lässt sich mit trap verhindern.

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
17Piping und Redirection
18tee
19alias
20Der Shebang
21Das sed Kommando
22cd Kommando
23case Verzweigungen
24Arrays
25Signale und trap
26Heredoc
27getopt

Signale

Für bestimmte Ereignisse sendet die bash ein Signal an dein Script, auf das du mit dem trap Kommando reagieren kannst.

Die verfügbaren Signale sind von Betriebssystem zu Betriebssystem unterschiedlich. Du kannst sie dir mit

trap -l

anzeigen lassen.

Liste der verfügbaren Signale auf einem Raspberry Pi 4 mit Raspberry Pi OS trixie
raspithek.de - Olli Graf
signal-listCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Liste der verfügbaren Signale auf einem Raspberry Pi 4 mit Raspberry Pi OS trixie

Die Namen aller Signale beginnen mit „SIG“, danach folgt abgekürzt, was signalisiert wird. Das ist etwas kryptisch. Das Signal SIGHUP ist eher noch historisch erhalten geblieben. Es signalisiert einen Hang Up, also, wenn die Datenleitung beendet wurde. Es stammt noch aus der Zeit der Einwählmodems.

SIGKILL wird signalisiert, wenn ein Prozess über das kill Kommando abgeschossen wird. Dieses ist nicht abfangbar.

Uns interessiert heute das SIGTERM, mit dem unserem Script signalisiert wird, dass es beendet wird.

Ausgangslage

Betrachten wir mal dieses Script:

#! /usr/bin/bash


touch /tmp/testfile

sleep 10
echo "Ende der Arbeit"

rm /tmp/testfile

Es legt unter /tmp eine temporäre Datei namens testfile an. Das sleep 10 steht für eine beliebige langwierige Aufgabe, die das Script erledigt. Wenn diese durchlaufen ist, wird die temporäre Datei wieder gelöscht.

Letzteres passiert aber nicht, wenn der User das Script mit CTRL-C abbricht. Dann wird es beendet, bevor es das rm Kommando ausführen kann. Die Datei bleibt dann so lange stehen, bis sie manuell entfernt wird. Jetzt mal dir aus, ein Script würde 1000 temporäre Dateien von mehreren 100 KByte Grösse anlegen. Dann würde die Speicherkarte das Raspis rasch volllaufen.

Das Script wurde vorzeitig abgebrochen und /tmp/testfile ist immer noch vorhanden.
raspithek.de - Olli Graf
notrapCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Das Script wurde vorzeitig abgebrochen und /tmp/testfile ist immer noch vorhanden.

SIGINT abfangen

Lass uns das mal verbessern. Wir benötigen eine Funktion zum Aufräumen und binden diese an das Signal.

#! /usr/bin/bash

cleanup() {
  echo "Programmende signalisiert."
  rm /tmp/testfile
}

trap cleanup exit
touch /tmp/testfile

sleep 10
echo "Ende der Arbeit"

Die Funktion cleanup() wird durch trap cleanup exit an das Signal gekoppelt. Immer, wenn das Script beendet wird, wird jetzt unsere Funktion aufgerufen. Dadurch können wir das Löschen von testfile in diese Funktion verlagern.

Beim Programmabbruch wird cleanup() aufgerufen und /tmp/testfile wird gelöscht.
raspithek.de - Olli Graf
trapCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Beim Programmabbruch wird cleanup() aufgerufen und /tmp/testfile wird gelöscht.

Auch, wenn das Programm ganz regulär durchläuft, wird nachher cleanup() aufgerufen.

Das Script läuft durch und cleanup() hat testfile gelöscht.
raspithek.de - Olli Graf
regular-exitCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Das Script läuft durch und cleanup() hat testfile gelöscht.

In der Überschrift steht SIGINT, die Scripts trappen aber exit. Warum ist das so? Mit SIGTERM signalisiert der Kernel das Ende des Scripts. Wir reagieren aber dann immer so als läge ein reguläres Programmende vor. Dadurch spart man sich ein Keyword.

Ablauf eines Signals

Was passiert jetzt eigentlich genau wenn du CTRL-C drückst? Der Kerneltreiber erkennt dies und sendet dem Terminaltreiber (also der bash) das SIGINT. Diese sorgt dafür, dass der Vordergrundprozess (also unser Script beendet wird. Wodurch das exit Signal ausgelöst wird, auf das wir dann reagieren.

trap ohne spezielle Funktion

trap führt immer den Programmcode aus, der vor dem Signalnamen steht. Das kann wie oben eine spezielle Funktion sein. Du kannst aber auch andere Kommandos dort platzieren.

#! /usr/bin/bash


trap "echo vorbei" SIGINT

touch /tmp/testfile

sleep 10
echo "Ende der Arbeit"

In dieser Variante wird bei SIGINT nur echo vorbei ausgeführt. Eine spezielle Funktion zur Behandlung des Signals ist nicht notwendig.Achte darauf, wie die Anführungszeichen gesetzt sind. Das gesamte auszuführende Kommando muss von ihnen umschlossen sein.

trap löschen

Um einen trap wieder aufzuheben, kannst du

trap - exit

verwenden. Dies ist nützlich, wenn du nur zwischenzeitlich auf ein Signal reagieren musst.

Fazit

Um beim Programmabbruch sauber aufzuräumen, kann dein Script auf Signale mit dem trap Kommando reagieren. In der Wikipedia gibt es eine Liste, die noch mehr Signale erklärt

Schreibe einen Kommentar

Insert math as
Block
Inline
Additional settings
Formula color
Text color
#333333
Type math using LaTeX
Preview
\({}\)
Nothing to preview
Insert
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.
raspithek.de - Olli Graf
WordPress Cookie Hinweis von Real Cookie Banner