trap
Capturer les interruptions en shell UNIX
Lorsqu'un shell UNIX s'achève soit de lui-même soit par une erreur (interuption par ctrl+C, une erreur de syntaxe ou de commande, ...) il se peut que les répertoires ne soient pas propres ou remis en état.
En effet, surtout dans le cas d'une fin en erreur, en fonction de l'endroit où le script s'est arrêté, les générations de fichiers et/ou de données n'étant pas finies, tout n'est pas forcément propre et cohérent. Dans certains cas, il peut même être utile d'exécuter un autre script en cas d'erreur afin, par exemple, d'envoyer un message d'alerte, effectuer une restauration ou une sauvegarde, ...
Malheureusement, pour réaliser tout cela il faut pouvoir réagir en fonction du type d'arrêt de script. trap est la commande qui permet justement de faire cela.
Syntaxe
trap 'commande' liste_de_signaux
Le numéro de signal correspond à ceux qu'on obtient avec la commande kill -l. Avec trap on peut soit utiliser le signal, soit son numéro.
# kill -l
1) HUP
2) INT
3) QUIT
4) ILL
5) TRAP
6) IOT
7) EMT
8) FPE
9) KILL
10) BUS
11) SEGV
12) SYS
13) PIPE
14) ALRM
15) TERM
16) USR1
17) USR2
18) CHLD
19) PWR
20) VTALRM
21) PROF
22) POLL
23) WINCH
24) STOP
25) TSTP
26) CONT
27) TTIN
28) TTOU
29) URG
30) LOST
31) RESERVED
32) DIL
33) XCPU
34) XFSZ
35) bad trap
36) bad trap
37) RTMIN
38) RTMIN+1
39) RTMIN+2
40) RTMIN+3
41) RTMAX-3
42) RTMAX-2
43) RTMAX-1
44) RTMAX
Signal | Signification |
---|---|
HUP | hangup : envoie un signal de réinitialisation |
INT | Interruption |
QUIT | Core dump : génère un fichier core. |
ILL | Le programme tente d'exécuter du code malformé, inconnu ou avec de mauvais privilèges |
TRAP | Le programme envoie un signal au débugger (message capturé) |
IOT | idem SIGABRT : interruption du programme |
EMT | emulator trap : un programme émulé ou virtualisé a posé problème |
FPE | floating-point exception : le programme a réalisé une opération arithmétique erronée |
KILL | arrête le programme immédiatement |
BUS | Le programme a causé une erreur de bus |
SEGV | Segmentation fault : le programme fait référence à un mauvais emplacement de mémoire |
SYS | Un mauvais argument est passé en paramètre |
PIPE | Un programme tente d'écrire dans un pipe sans processus connecté à l'autre bout |
ALRM | La limite de temps est dépassée |
TERM | Envoie un signal au programme pour le terminer |
USR1/USR2 | Envoie un signal dans des conditions définies par un utilisateur |
CHLD/CLD | child : signal envoyé par un programme lorsqu'un processus fils est achevé |
PWR | power : le système subit un problème d'alimentation |
VTALRM | virtual alarm : signal envoyé lorsque le temps limite a été dépassé |
PROF | profiler : signal envoyé lorsqu'un timer a expiré |
POLL | polling : un problème est survenu lors d'un événement I/O asynchrone |
WINCH | window [size] change : signal envoyé au programme lorsque la fenêtre de contrôle change de taille |
STOP | signal demandant au programme de se suspendre |
TSTP | tty stop : signal envoyé au programme lorsqu'un terminal suspend ses requêtes |
CONT | Redémarre un programme suspendu par STOP |
TTIN | Le programme tente de lire tty alors qu'il est en arrière-plan |
TTOU | Le programme tente d'écrire sur tty alors qu'il est en arrière-plan |
URG | Un socket a une donnée urgente à lire |
LOST | Le verrou d'un fichier a été perdu |
XCPU | Le programme a utilisé le CPU prend trop longtemps |
XFSZ | Le fichier a dépassé la taille maximale autorisée |
RTMIN/RTMIN+n | real-time minimum : signaux définis par l'application |
RTMAX/RTMAX-n | real-time maximum : signaux définis par l'application |
remarque
Il existe aussi des pseudo signaux comme le signal 0 (EXIT) qui est la valeur retournée par la fin sans erreur d'un script. C'est aussi la valeur retournée par le shell lors de la déconnexion.
La commande est soit une (liste de) commande(s) exécutée(s) en direct soit un appel de fonction.
Le commande trap sert dans deux cas bien distincts :
demander à une action qui s'interrompt en erreur ou qu'on veut interrompre d'effectuer une ou plusieurs commandes avant d'arrêter le traitement. Par exemple :
empêcher qu'une séquence de commandes ne soit interrompue par la réception d'un signal.
trap "echo FIN; exit 0" 2 3 15
trap "" 1 2 3 15 # ignorer les signaux
commande
...
trap 1 2 3 15 # revenir à l'état par défaut
Exemples
Empêcher l'interruption d'un programme
#!/bin/sh
trap "" 2 3 15 # ignorer les signaux
while :
do
echo "Entrez le mot de passe : \c"
read mdp
if [ "${mdp}" = "test" ]
then
echo "mot de passe valide !"
break
fi
done
trap 2 3 15 # revenir à l'état par défaut
Cet exemple montre que la boucle ne peut pas être interrompue, sauf par l'entrée du bon mot de passe. En effet, le script commence par mettre de côté les signaux en leur affectant une exécution vide. trap ne remettra en place correcte le contexte qui si la boucle s'achève avec succès (entrée du bon mot de passe). Ainsi, l'utilisateur, quoi qu'il fasse ne peut pas interrompre le programme.
Ignorer un signal
trap "" 2 # ignorer le signal
Ignorer un ensemble de signaux
trap "" 2 3 15 # ignorer les signaux
Revenir à l'action par défaut
trap 2 # retablir la situation
Utiliser les mnémoniques
trap "echo CTRL-C" INT # retablir la situation
Exécuter un script à la déconnexion
Pour exécuter un script automatiquement à la déconnexion, il faut d'abord ajouter au fichier .profile :
trap "~/logoff" 0
Puis créer le script logoff en question :
#!/bin/sh
rm /tmp/*.tmp
clear
echo "Suppression des fichiers temporaires terminée"
echo "Déconnexion..."
Ne pas oublier de rendre le script exécutable...