Bash
Utiliser "trap" pour réagir aux signaux et aux événements du système
Recherche…
Syntaxe
- action piège sigspec ... # Exécuter "action" sur une liste de signaux
- piège sigspec ... # Omettre l'action réinitialise les traps pour les signaux
Paramètres
Paramètre | Sens |
---|---|
-p | Liste des pièges actuellement installés |
-l | Liste des noms de signaux et numéros correspondants |
Remarques
Le trap
utilitaire est une enveloppe spéciale intégrée. Il est défini dans POSIX , mais bash ajoute également des extensions utiles.
Les exemples compatibles avec POSIX commencent par #!/bin/sh
et les exemples commençant par #!/bin/bash
utilisent une extension bash.
Les signaux peuvent être soit un numéro de signal, un nom de signal (sans le préfixe SIG), soit le mot-clé spécial EXIT
.
Ceux garantis par POSIX sont:
Nombre | prénom | Remarques |
---|---|---|
0 | SORTIE | Toujours exécuter à la sortie du shell, quel que soit le code de sortie |
1 | SIGHUP | |
2 | SIGINT | C'est ce que ^C envoie |
3 | SIGQUIT | |
6 | SIGABRT | |
9 | SIGKILL | |
14 | SIGALRM | |
15 | SIGTERM | C'est ce que kill envoie par défaut |
SIGINT de capture ou Ctl + C
Le piège est réinitialisé pour les sous-couches, de sorte que le sleep
agira toujours sur le signal SIGINT
envoyé par ^C
(généralement en quittant), mais le processus parent (c'est-à-dire le script shell) ne le fera pas.
#!/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
Et une variante qui vous permet encore de quitter le programme principal en appuyant deux fois sur ^C
:
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
Introduction: nettoyer les fichiers temporaires
Vous pouvez utiliser la commande trap
pour "piéger" les signaux; c'est l'équivalent shell de l'appel signal()
ou sigaction()
en C et de la plupart des autres langages de programmation pour capter les signaux.
L'une des utilisations les plus courantes de trap
est de nettoyer les fichiers temporaires à la sortie attendue et inattendue.
Malheureusement, pas assez de scripts shell le font :-(
#!/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.
Cumulez une liste de trappes à exécuter à la sortie.
Avez-vous déjà oublié d'ajouter un trap
pour nettoyer un fichier temporaire ou d'autres travaux à la sortie?
Avez-vous déjà mis un piège qui a annulé un autre?
Ce code facilite l'ajout d'éléments à la sortie d'un élément à la fois, plutôt que d'avoir une seule instruction trap
quelque part dans votre code, ce qui peut être facile à oublier.
# 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
}
Tuer les processus de l'enfant à la sortie
Les expressions pièges ne doivent pas nécessairement être des fonctions ou des programmes individuels, elles peuvent également être des expressions plus complexes.
En combinant jobs -p
et kill
, nous pouvons tuer tous les processus enfants générés par le shell à la sortie:
trap 'jobs -p | xargs kill' EXIT
réagir au changement de taille de la fenêtre des terminaux
Il y a un signal WINCH (WINdowCHange), qui est déclenché quand on redimensionne une fenêtre de terminal.
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