Les touches de signal telles que Ctrl+ Cenvoient un signal à tous les processus du groupe de processus de premier plan .
Dans le cas typique, un groupe de processus est un pipeline. Par exemple, dans head <somefile | sort, le processus en cours d'exécution headet le processus en cours d'exécution sortsont dans le même groupe de processus, tout comme le shell, de sorte qu'ils reçoivent tous le signal. Lorsque vous exécutez un travail en arrière-plan ( somecommand &), ce travail se trouve dans son propre groupe de processus, donc appuyer sur Ctrl+ Cne l'affecte pas.
Le timeoutprogramme se place dans son propre groupe de processus. Du code source:
/* Ensure we're in our own group so all subprocesses can be killed.
Note we don't just put the child in a separate group as
then we would need to worry about foreground and background groups
and propagating signals between them. */
setpgid (0, 0);
Lorsqu'un délai d'expiration se produit, timeoutpasse par le simple moyen de tuer le groupe de processus dont il est membre. Puisqu'il s'est placé dans un groupe de processus séparé, son processus parent ne sera pas dans le groupe. L'utilisation d'un groupe de processus ici garantit que si l'application enfant se transforme en plusieurs processus, tous ses processus recevront le signal.
Lorsque vous exécutez timeoutdirectement sur la ligne de commande et appuyez sur Ctrl+ C, le SIGINT résultant est reçu à la fois par timeoutet par le processus enfant, mais pas par le shell interactif qui est timeoutle processus parent. Quand timeoutest appelé à partir d'un script, seul le shell exécutant le script reçoit le signal: timeoutne l'obtient pas car il se trouve dans un groupe de processus différent.
Vous pouvez définir un gestionnaire de signal dans un script shell avec la fonction trapintégrée. Malheureusement, ce n'est pas si simple. Considère ceci:
#!/bin/sh
trap 'echo Interrupted at $(date)' INT
date
timeout 5 sleep 10
date
Si vous appuyez sur Ctrl+ Caprès 2 secondes, cela attend toujours les 5 secondes complètes, puis imprimez le message «Interrompu». En effet, le shell s'abstient d'exécuter le code d'interruption lorsqu'un travail de premier plan est actif.
Pour y remédier, exécutez le travail en arrière-plan. Dans le gestionnaire de signaux, appelez killpour relayer le signal au timeoutgroupe de processus.
#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid
bgoffg. Quoi qu'il en soit, y a-t-il une différence entre vos 1er et 3e exemples?