Bash
Używanie „pułapki” do reagowania na sygnały i zdarzenia systemowe
Szukaj…
Składnia
- trap action sigspec ... # Uruchom „action” na liście sygnałów
- trap sigspec ... # Pominięcie akcji resetuje pułapki na sygnały
Parametry
Parametr | Znaczenie |
---|---|
-p | Wyświetl aktualnie zainstalowane pułapki |
-l | Wymień nazwy sygnałów i odpowiadające im numery |
Uwagi
Narzędzie trap
jest specjalną wbudowaną powłoką. Jest zdefiniowany w POSIX , ale bash dodaje także kilka przydatnych rozszerzeń.
Przykłady zgodne z POSIX zaczynają się od #!/bin/sh
, a przykłady zaczynające się od #!/bin/bash
używają rozszerzenia bash.
Sygnały mogą być numerem sygnału, nazwą sygnału (bez prefiksu SIG) lub słowem kluczowym EXIT
.
Gwarancje POSIX to:
Numer | Nazwa | Notatki |
---|---|---|
0 | WYJŚCIE | Zawsze uruchamiaj przy wyjściu z powłoki, niezależnie od kodu wyjścia |
1 | SIGHUP | |
2) | SIGINT | Oto, co przesyła ^C |
3) | SIGQUIT | |
6 | SIGABRT | |
9 | SIGKILL | |
14 | SIGALRM | |
15 | SIGTERM | To domyślnie wysyła kill |
Łapanie SIGINT lub Ctl + C
Pułapka jest resetowana dla podpowłok, więc sleep
nadal będzie działał na sygnał SIGINT
wysyłany przez ^C
(zwykle przez wyjście), ale proces nadrzędny (tj. Skrypt powłoki) nie.
#!/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
I wariant, który wciąż pozwala wyjść z programu głównego, naciskając ^C
dwa razy na sekundę:
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
Wprowadzenie: wyczyść pliki tymczasowe
Możesz użyć polecenia trap
do „pułapkowania” sygnałów; jest to odpowiednik powłoki wywołania signal()
lub sigaction()
w C i większości innych języków programowania do przechwytywania sygnałów.
Jednym z najczęstszych zastosowań trap
jest czyszczenie plików tymczasowych przy oczekiwanym i nieoczekiwanym wyjściu.
Niestety nie robi tego wystarczająca liczba skryptów powłoki :-(
#!/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.
Zbierz listę prac pułapek do uruchomienia przy wyjściu.
Czy kiedykolwiek zapomniałeś dodać trap
aby wyczyścić plik tymczasowy lub wykonać inną pracę przy wyjściu?
Czy kiedykolwiek ustawiłeś jedną pułapkę, która anulowała inną?
Ten kod ułatwia dodawanie czynności do wykonania przy wyjściu z jednego elementu na raz, zamiast posiadania jednej dużej instrukcji trap
gdzieś w kodzie, co może być łatwe do zapomnienia.
# 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
}
Zabijanie procesów potomnych przy wyjściu
Wyrażenia pułapek nie muszą być pojedynczymi funkcjami lub programami, mogą być również bardziej złożonymi wyrażeniami.
Łącząc jobs -p
i kill
, możemy zabić wszystkie odrodzone procesy potomne powłoki przy wyjściu:
trap 'jobs -p | xargs kill' EXIT
reagują na zmianę rozmiaru okna terminali
Jest sygnał WINCH (WINdowCHange), który jest uruchamiany, gdy zmienia się rozmiar okna terminala.
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