Bash
Använda "fälla" för att reagera på signaler och systemhändelser
Sök…
Syntax
- fälla action sigspec ... # Kör "action" i en lista över signaler
- trap sigspec ... # Utelämnande av åtgärder återställer fällor för signaler
parametrar
Parameter | Menande |
---|---|
-p | Lista för närvarande installerade fällor |
-l | Lista signalnamn och motsvarande nummer |
Anmärkningar
trap
är ett speciellt inbyggt skal. Det definieras i POSIX , men bash lägger till några användbara tillägg också.
Exempel som är POSIX-kompatibla börjar med #!/bin/sh
, och exempel som börjar med #!/bin/bash
använder en bash-förlängning.
Signalerna kan antingen vara ett signalnummer, ett signalnamn (utan SIG-prefixet) eller det speciella nyckelordet EXIT
.
De som garanteras av POSIX är:
siffra | namn | anteckningar |
---|---|---|
0 | UTGÅNG | Kör alltid vid skalutgång, oavsett utgångskod |
1 | SIGHUP | |
2 | SIGINT | Det här är vad ^C skickar |
3 | SIGQUIT | |
6 | SIGABRT | |
9 | SIGKILL | |
14 | SIGALRM | |
15 | SIGTERM | Det här är vad kill skickar som standard |
Fånga SIGINT eller Ctl + C
Fällan återställs för underskal, så sleep
kommer fortfarande att fungera på SIGINT
signalen som skickas av ^C
(vanligtvis genom att sluta), men överordnadsprocessen (dvs skalskriptet) kommer inte.
#!/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
Och en variant som fortfarande låter dig avsluta huvudprogrammet genom att trycka på ^C
två gånger på en 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
Introduktion: rensa upp tillfälliga filer
Du kan använda trap
kommandot för att "fälla" signaler; detta är skalekvivalenten för signal()
eller sigaction()
kallar C och de flesta andra programmeringsspråk för att fånga signaler.
En av de vanligaste användningarna av trap
är att rensa upp tillfälliga filer på både en förväntad och oväntad utgång.
Tyvärr gör inte tillräckligt med skalskript :-(
#!/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.
Samla en lista över fällearbeten för att köra vid utgången.
Har du någonsin glömt att lägga till en trap
att rensa upp en tillfällig fil eller göra annat arbete vid utgången?
Har du någonsin satt en fälla som avbröt en annan?
Den här koden gör det enkelt att lägga till saker som ska göras vid avslutande av ett objekt åt gången, snarare än att ha ett stort trap
någonstans i din kod, vilket kan vara lätt att glömma.
# 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
}
Döda barnprocesser vid utgång
Fälluttryck behöver inte vara enskilda funktioner eller program, de kan också vara mer komplexa uttryck.
Genom att kombinera jobs -p
och kill
kan vi döda alla spawnade barnprocesser i skalet vid utgången:
trap 'jobs -p | xargs kill' EXIT
reagera på ändring av terminalfönsterstorlek
Det finns en signal WINCH (WINdowCHange), som avfyras när man ändrar storlek på ett terminalfönster.
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