Tuer -INT ne fonctionne pas sur le script bash avec le jeu de pièges INT

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.