Que ce passe-t-il
Lorsque vous appuyez sur Ctrl+ C, le SIGINT
signal est envoyé à l'ensemble du groupe de processus de premier plan . Ici, il est envoyé à la fois au find
processus et au processus shell appelant. find
réagit en sortant immédiatement, et l'obus réagit en appelant le piège.
Si le code dans le piège revient (c'est-à-dire qu'il n'appelle pas exit
), l'exécution se poursuit avec la commande après celle qui a été interrompue par le signal. Ici, après la find
commande vient la fin du script, donc le script se ferme immédiatement de toute façon. Mais vous pouvez voir la différence entre entrer 0 et 1 en ajoutant une autre commande:
find /
echo "find returned $?"
Une façon de faire ce que vous voulez (mais que vous ne devriez probablement pas faire)
Tu peux faire ce que tu veux; mais cette partie de ma réponse concerne davantage la découverte de la programmation shell que la résolution d'un problème réel.
- En termes de conception, un signal redémarrable n'est pas ce à quoi vous vous attendez normalement dans le genre de programmes relativement simples que les scripts shell sont normalement. On s'attend à ce que Ctrl+ Ctue le script.
- Comme vous le verrez ci-dessous, il étend de toute façon les capacités du shell.
Si vous voulez éviter de tuer find
, vous devez commencer dans l' arrière - plan : find / &
. Utilisez ensuite la fonction wait
intégrée pour attendre qu'elle se termine normalement. Un signal interrompra la fonction wait
intégrée, que vous pourrez exécuter en boucle jusqu'à ce que vous receviez un signal que vous souhaitez propager. Ensuite, utilisez kill
pour tuer le travail.
hell () {
echo "Do you want to quit? Press 1 for yes and 0 for no"
read n
if [ "$n" = 1 ]; then
# Kill the job if it's running, then exit
if [ -n "$job_pid" ]; then kill $job_pid; fi
exit 1
fi
}
job_pid=
trap "hell" SIGINT
# Start a demo job in the background
for i in 1 2 3 4 5; do date; sleep 1; done &
job_pid=$!
# Call wait in a loop; wait will return 0 if the job exits, and 128+$signum if interrupted by a signal.
while ! wait; do
echo "resuming wait"
done
job_pid=
echo last exit code: $?
Il y a des limites à cette approche dans le shell:
- Il y a une condition de concurrence: si vous appuyez sur Ctrl+ Cjuste après la fin du travail mais avant la
job_pid=
ligne, le gestionnaire de signal essaiera de tuer $jobpid
, mais le processus n'existe plus (même en tant que zombie, car il l' wait
a déjà récolté), et le processus L'ID peut avoir été réutilisé par un autre processus. Ce n'est pas facilement réparable dans le shell (peut-être en définissant un gestionnaire pour SIGCHLD
?).
- Si vous avez besoin du statut de retour de l'emploi, vous devez utiliser le
wait $job_pid
formulaire. Mais alors vous ne pouvez pas distinguer «a wait
été interrompu par un signal» de «le travail a été tué par un signal» (ni de «le travail a été interrompu de lui-même avec un statut de retour ≥128», mais c'est un fait général en gros programmation).
- Cela ne s'étendra pas facilement, voire pas du tout, à plusieurs sous-jobs. Notez que le comportement des pièges et des signaux est souvent surprenant lorsque vous allez au-delà des bases de la plupart des implémentations de shell (seul ksh le fait bien).
Pour surmonter ces limitations, utilisez un langage plus sophistiqué comme Perl ou Python.