Bash
Utilizzo di "trap" per reagire ai segnali e agli eventi di sistema
Ricerca…
Sintassi
- trap action sigspec ... # Esegui "action" su un elenco di segnali
- trap sigspec ... # Omitting action reimposta i trap per i segnali
Parametri
Parametro | Senso |
---|---|
-p | Elenca le trap attualmente installate |
-l | Elenca i nomi dei segnali e i numeri corrispondenti |
Osservazioni
L'utilità trap
è un built-in shell speciale. È definito in POSIX , ma bash aggiunge anche alcune estensioni utili.
Gli esempi compatibili con POSIX iniziano con #!/bin/sh
e gli esempi che iniziano con #!/bin/bash
usano un'estensione bash.
I segnali possono essere sia un numero di segnale, un nome di segnale (senza il prefisso SIG), o la parola chiave speciale EXIT
.
Quelle garantite da POSIX sono:
Numero | Nome | Gli appunti |
---|---|---|
0 | USCITA | Esegui sempre all'uscita dalla shell, indipendentemente dal codice di uscita |
1 | SIGHUP | |
2 | SIGINT | Questo è ciò che ^C invia |
3 | SIGQUIT | |
6 | SIGABRT | |
9 | SIGKILL | |
14 | SIGALRM | |
15 | SIGTERM | Questo è ciò che kill invia di default |
Cattura SIGINT o Ctl + C
La trappola viene reimpostata per le subshell, quindi il sleep
agirà comunque sul segnale SIGINT
inviato da ^C
(solitamente chiudendo), ma il processo genitore (cioè lo script della shell) non lo farà.
#!/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
E una variante che ti consente ancora di uscire dal programma principale premendo ^C
due volte in un secondo:
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
Introduzione: ripulire i file temporanei
È possibile utilizzare il comando trap
per "trap" i segnali; questo è l'equivalente di shell della chiamata signal()
o sigaction()
in C e la maggior parte degli altri linguaggi di programmazione per rilevare i segnali.
Uno degli usi più comuni di trap
è quello di pulire i file temporanei sia in uscita prevista che inattesa.
Sfortunatamente non bastano script di shell per fare questo :-(
#!/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.
Accumula un elenco di operazioni di trap da eseguire all'uscita.
Ti sei mai dimenticato di aggiungere una trap
per pulire un file temporaneo o eseguire altri lavori all'uscita?
Hai mai impostato una trappola che ne ha annullato un'altra?
Questo codice semplifica l'aggiunta di elementi da eseguire all'uscita di un elemento alla volta, piuttosto che avere un'istruzione trap
grandi dimensioni da qualche parte nel codice, che potrebbe essere facile da dimenticare.
# 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
}
Killing Child Processes in uscita
Le espressioni trap non devono essere singole funzioni o programmi, ma possono anche essere espressioni più complesse.
Combinando jobs -p
e kill
, possiamo eliminare tutti i processi figli spawnati della shell all'uscita:
trap 'jobs -p | xargs kill' EXIT
reagire al cambiamento della dimensione della finestra dei terminali
C'è un segnale WINCH (WINdowCHange), che viene attivato quando si ridimensiona una finestra di terminale.
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