Bash
Verwendung von "Trap", um auf Signale und Systemereignisse zu reagieren
Suche…
Syntax
- trap action sigspec ... # "action" für eine Liste von Signalen ausführen
- trap sigspec ... # Wenn keine Aktion ausgeführt wird, werden Traps für Signale zurückgesetzt
Parameter
Parameter | Bedeutung |
---|---|
-p | Listet die aktuell installierten Fallen auf |
-l | Listen Sie Signalnamen und entsprechende Nummern auf |
Bemerkungen
Das trap
Dienstprogramm ist eine spezielle Shell. Es ist in POSIX definiert , aber bash fügt auch einige nützliche Erweiterungen hinzu.
Beispiele, die POSIX-kompatibel sind, beginnen mit #!/bin/sh
, und Beispiele, die mit #!/bin/bash
verwenden eine Bash-Erweiterung.
Die Signale können entweder eine Signalnummer, ein Signalname (ohne SIG-Präfix) oder das Spezialschlüsselwort EXIT
.
Die von POSIX garantierten sind:
Nummer | Name | Anmerkungen |
---|---|---|
0 | AUSFAHRT | Immer beim Shell-Exit ausführen, unabhängig vom Exit-Code |
1 | SEUFZEND | |
2 | SIGINT | Dies ist, was ^C sendet |
3 | SIGQUIT | |
6 | SIGABRT | |
9 | Sigkill | |
14 | SIGALRM | |
fünfzehn | SIGTERM | Dies ist, was kill standardmäßig sendet |
Fang von SIGINT oder Ctl + C
Der Trap wird für Subshells zurückgesetzt, daher wirkt sich der sleep
weiterhin auf das von ^C
gesendete SIGINT
Signal aus (normalerweise durch Beenden), der übergeordnete Prozess (dh das Shell-Skript) jedoch nicht.
#!/bin/sh
# Run a command on signal 2 (SIGINT, which is what ^C sends)
sigint() {
echo "Killed subshell!"
}
trap sigint INT
# Or use the no-op command for no output
#trap : INT
# This will be killed on the first ^C
echo "Sleeping..."
sleep 500
echo "Sleeping..."
sleep 500
Und eine Variante, bei der Sie das Hauptprogramm noch durch zweimaliges Drücken von ^C
beenden können:
last=0
allow_quit() {
[ $(date +%s) -lt $(( $last + 1 )) ] && exit
echo "Press ^C twice in a row to quit"
last=$(date +%s)
}
trap allow_quit INT
Einleitung: Bereinigen Sie temporäre Dateien
Mit dem trap
Befehl können Sie Signale "einfangen". Dies ist das Shell-Äquivalent des Aufrufs signal()
oder sigaction()
in C und den meisten anderen Programmiersprachen, um Signale sigaction()
.
Eine der häufigsten Anwendungen von trap
ist das Bereinigen temporärer Dateien bei einem erwarteten und einem unerwarteten Exit.
Leider tun nicht genug Shell-Skripte das :-(
#!/bin/sh
# Make a cleanup function
cleanup() {
rm --force -- "${tmp}"
}
# Trap the special "EXIT" group, which is always run when the shell exits.
trap cleanup EXIT
# Create a temporary file
tmp="$(mktemp -p /tmp tmpfileXXXXXXX)"
echo "Hello, world!" >> "${tmp}"
# No rm -f "$tmp" needed. The advantage of using EXIT is that it still works
# even if there was an error or if you used exit.
Sammeln Sie eine Liste der Trap-Arbeiten, die beim Beenden ausgeführt werden sollen.
Haben Sie schon einmal vergessen, eine trap
hinzuzufügen, um eine temporäre Datei zu bereinigen, oder machen Sie andere Aufgaben beim Beenden?
Haben Sie jemals eine Falle gestellt, die eine andere stornierte?
Dieser Code macht es einfach, Dinge hinzuzufügen, die beim Beenden eines Elements gleichzeitig ausgeführt werden müssen, anstatt eine große trap
Anweisung irgendwo im Code zu haben, was leicht zu vergessen ist.
# on_exit and add_on_exit
# Usage:
# add_on_exit rm -f /tmp/foo
# add_on_exit echo "I am exiting"
# tempfile=$(mktemp)
# add_on_exit rm -f "$tempfile"
# Based on http://www.linuxjournal.com/content/use-bash-trap-statement-cleanup-temporary-files
function on_exit()
{
for i in "${on_exit_items[@]}"
do
eval $i
done
}
function add_on_exit()
{
local n=${#on_exit_items[*]}
on_exit_items[$n]="$*"
if [[ $n -eq 0 ]]; then
trap on_exit EXIT
fi
}
Kinderprozesse beim Beenden töten
Trap-Ausdrücke müssen keine einzelnen Funktionen oder Programme sein, sie können auch komplexere Ausdrücke sein.
Durch das Kombinieren von jobs -p
und kill
können Sie beim Beenden alle untergeordneten Prozesse der Shell beenden:
trap 'jobs -p | xargs kill' EXIT
reagieren auf Änderung der Fenstergröße der Terminals
Es gibt ein Signal WINCH (WINdowCHange), das ausgelöst wird, wenn die Größe eines Terminalfensters geändert wird.
declare -x rows cols
update_size(){
rows=$(tput lines) # get actual lines of term
cols=$(tput cols) # get actual columns of term
echo DEBUG terminal window has no $rows lines and is $cols characters wide
}
trap update_size WINCH