Considérons le script bash suivant:
#!/bin/bash echo "Setting trap" trap 'ctrl_c' INT function ctrl_c() { echo "CTRL+C pressed" exit } sleep 1000
En l’appelant ./s
, il va dormir. Si vous appuyez sur Ctrl + C, il imprime le message et quitte.
Appelez-le maintenant, ouvrez un autre terminal et tuez le PID correspondant avec l’option -INT. Cela ne marche pas ou ne fait rien. Pourquoi?
Kill sans flags fonctionne mais n’appelle pas la fonction ctrl_c ().
A partir du standard POSIX pour le shell :
Lorsqu’un signal pour lequel une interruption a été définie est reçu pendant que le shell attend la fin d’un utilitaire exécutant une commande de premier plan, l’interruption associée à ce signal ne doit pas être exécutée tant que la commande de premier plan n’est pas terminée.
Pour vérifier cela, nous pouvons exécuter strace
sur le shell exécutant votre script. En envoyant le SIGINT
depuis un autre terminal, bash note simplement que le signal a été reçu et revient à attendre que son enfant, la commande de sumil, se termine:
rt_sigaction(SIGINT, {0x808a550, [], 0}, {0x80a4600, [], 0}, 8) = 0 waitpid(-1, 0xbfb56324, 0) = ? ERESTARTSYS --- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=3556, si_uid=1000} --- sigreturn({mask=[CHLD]}) = -1 EINTR (Interrupted system call) waitpid(-1,
Pour que kill
ait le même effet que Ctrl-C , vous devez envoyer SIGINT
au groupe de processus . Le shell par défaut mettra chaque processus d’une nouvelle commande dans son propre pgrp:
$ ps -f -o pid,ppid,pgid,tty,comm -t pts/1 PID PPID PGID TT COMMAND 3460 3447 3460 pts/1 bash 29087 3460 29087 pts/1 \_ foo.sh 29120 29087 29087 pts/1 \_ sleep $ kill -2 -29087
Et maintenant, le piège court et le shell sort:
waitpid(-1, [{WIFSIGNALED(s) && WTERMSIG(s) == SIGINT}], 0) = 29120 --- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=3556, si_uid=1000} --- sigreturn({mask=[CHLD]}) = 29120 ... write(1, "CTRL+C pressed\n", 15) = 15 ... exit_group(0) = ?
Lorsque nous utilisons la commande ps aux pour trouver les valeurs PID, nous voyons qu’il y a 2 processus, ce programme et le sumil. Le processus du programme n’interrompt pas avec le paramètre -INT comme vous le dites. Cependant, lorsque le paramètre -2 ou -INT (même sens) est utilisé pour le processus de veille, le processus est interrompu comme prévu. Le message s’imprime et s’arrête. Je ne comprenais pas pourquoi le processus principal ne s’arrêtait pas, mais je voulais montrer que le processus de sumil pouvait être interrompu par cette méthode. J’espère que ce sera bon pour toi.
sleep
n’est pas un shell intégré:
$ which sleep /bin/sleep
Cela signifie que lorsque vous exécutez sleep
il s’exécutera comme un processus enfant distinct. Lorsqu’un processus enfant est créé, diverses choses sont copiées de parent à enfant ( héritées ) et l’une d’entre elles est le masque de signalisation. Note: seulement le masque. Donc, si vous aviez défini:
trap '' INT
alors le sleep
aurait hérité de cela – cela signifie ignorer le signal. Cependant, dans votre cas, vous vous attendez à ce que sleep
(qui est probablement écrit en C) exécute une fonction bash
. Non peut faire – mauvaise langue pour commencer. Imaginez: il faudrait exécuter bash
pour exécuter la fonction bash.
Avertissements – les détails concernant le traitement du signal peuvent varier d’une plate-forme à l’autre.
Il est possible de faire sleep
une version intégrée, voir ici mais cela pose probablement plus de problèmes que cela en vaut la peine.