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 :

  • trap "echo FIN; exit 0" 2 3 15
  • empêcher qu'une séquence de commandes ne soit interrompue par la réception d'un signal.

  • 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...