Vous voulez améliorer cette question ? Ajoutez des détails et clarifiez le problème en modifiant ce message.
Fermé il y a 3 ans.
Améliorer cette question
Pour comprendre
Si Bash attend qu'une commande se termine et reçoit un signal
pour lequel un déroutement a été défini, le déroutement ne sera pas exécuté tant que
la commande ne sera pas terminée.Lorsque Bash attend une commande asynchrone via la commande intégrée wait ,
la réception d'un signal pour lequel un déroutement a été défini entraînera le retour immédiat de la
commande intégrée wait avec un état de sortie supérieur à
128, immédiatement après lequel le déroutement est exécuté.
à partir du manuel de Bash,
j'exécute ce qui suit :
-
Dans mes deux exemples, SIGINT (envoyé avec Ctrl-C) termine un
travail de premier plan (le premier cas dans le devis) et un travail d'arrière-plan
(le deuxième cas dans le devis) tous les deux immédiatement, sans attendre pour
qu'ils terminent.La première phrase de la citation signifie-t-elle que si Bash exécute une
tâche de premier plan et reçoit le signalSIGINT
, le piège du signalSIGINT
, lorsqu'il est défini, sera exécuté jusqu'à ce que la commande se termine ?
Si oui, pourquoi dans mon premier exemple, est-ce quectrl-C
faire en sorte que la tâche de premier plan
existe immédiatement avant qu'elle puisse se terminer ?$ sleep 10000 # a foreground job ^C $ sleep 10000 & # a background job [1] 21219 $ wait 21219 ^C $ echo $? 130
-
Que signifie "un signal pour lequel un piège a été tendu" veux dire,
-
un signal
arg
dont le trap a été spécifié viatrap arg sigspec
, ou -
un signal qui n'est pas ignoré, ou
-
un signal dont le trap n'est pas celui par défaut ?
Dans les exemples de ma partie 1, je n'ai pas configuré de trap pour SIGINT, donc le signal a son
gestionnaire par défaut (qui sort de toute boucle en cours d'exécution). Un
signal a-t-il son gestionnaire par défaut considéré comme ayant un piège
tendu ? -
-
J'ai mis en place un piège pour
SIGINT
, maisctrl-C
fera sortir la commande suivante
avant de se terminer. Alors est-ce contraire à la première
phrase de ma citation ?$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
Avant de définir le piège pour
SIGINT
,ctrl-C
fera également sortir
la même commande avant de terminer. Alors est-ce contraire à la première
phrase de ma citation ?$ bash -c 'sleep 10; echo "$?"' ^C
-
Pourriez-vous donner quelques exemples pour expliquer ce que signifient les deux phrases de
la citation ?
Merci.
Réponse acceptée :
Que signifie "un signal pour lequel un piège a été défini" ?
C'est un signal pour lequel un handler a été défini (avec trap 'handling code' SIG
) où le code de traitement n'est pas vide car cela entraînerait l'ignorance du signal.
Ainsi, les signaux qui ont leur disposition par défaut ne sont pas des signaux pour lesquels un piège a été défini.
Une partie de cette citation dans votre message s'applique également aux signaux qui ont leur disposition par défaut, bien qu'évidemment pas la partie sur l'exécution du piège , car aucun piège n'a été défini pour eux.
Le manuel parle de la livraison du signal au shell , pas aux commandes que vous exécutez à partir de ce shell.
1.
Si Bash attend qu'une commande se termine et reçoit un signal pour lequel un déroutement a été défini, le déroutement ne sera pas exécuté tant que la commande ne sera pas terminée.
(1)
pourquoi dans mon premier exemple, ctrl-C fait-il quitter le travail de premier plan immédiatement avant qu'il ne puisse se terminer
Si vous exécutez sleep 10
à l'invite d'un shell interactif , le shell mettra ce travail au premier plan (via un ioctl()
sur le périphérique tty qui indique à la discipline de la ligne terminale quel groupe de processus est celui de premier plan), donc seulement sleep
obtiendra un SIGINT sur ^C
et le shell interactif ne le fera pas , il n'est donc pas utile de tester ce comportement.
-
Le shell parent, car il est interactif, ne recevra pas le SIGINT car son processus n'est pas dans le groupe de processus de premier plan.
-
Chaque commande est libre de gérer les signaux à sa guise.
sleep
ne fait rien de spécial avec SIGINT, obtiendra donc la disposition par défaut (terminer) à moins que SIGINT ait été ignoré au démarrage.
(2) Si vous exécutez sleep 10
dans un shell non interactif ,
bash -c 'sleep 10; echo "$?"'
Les deux bash
non interactifs shell et sleep
recevra le SIGINT lorsque vous appuyez sur Ctrl-C.
Si bash
sorti tout de suite, il pourrait laisser le sleep
commande s'exécutant sans surveillance en arrière-plan s'il arrivait d'ignorer ou de gérer le signal SIGINT. Donc, à la place,
bash
comme la plupart des autres shells, blocs la réception de signaux (au moins certains signaux) lors de l'attente de commandes.- La livraison reprend après la sortie de la commande (après quoi les interruptions sont exécutées). Cela évite également que les commandes dans les interruptions s'exécutent en même temps que d'autres commandes.
Dans cet exemple ci-dessus, sleep
mourra sur SIGINT, donc bash
n'a pas longtemps à attendre pour gérer son propre SIGINT (ici pour mourir car je n'ai pas ajouté de trap
sur SIGINT).
(3) lorsque vous appuyez sur Ctrl+C lors de l'exécution du shell non interactif :
bash -c 'sh -c "trap "" INT; sleep 3"; echo "$?"'
(sans trap
sur SIGINT) bash
n'est pas tué par le SIGINT. bash
, comme quelques autres shells traitent SIGINT et SIGQUIT spécialement. Ils implémentent l'attente et sortie coopérative comportement décrit sur https://www.cons.org/cracauer/sigint.html (et est connu pour causer quelques désagréments comme les scripts appelant les commandes de gestion SIGINT qui ne peuvent pas être interrompues avec ^C
)
(4) Pour tester correctement, vous devez exécuter un bash
non interactif qui a défini un piège SIGINT et appelle une commande qui ne meurt pas immédiatement après SIGINT comme :
bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 3"'
bash
attend sh
qui a (avec sleep
) SIGINT ignoré (à cause du trap "" INT
), donc SIGINT ne tuera pas sleep
ni sh
. bash
n'ignore pas SIGINT, mais sa gestion est différée jusqu'à sh
Retour. Vous voyez Ouch
affiché, pas sur Ctrl+C , mais après sleep
et sh
se sont terminés normalement.
Notez que le trap
La commande définit un piège pour un signal pour le même shell dans lequel elle s'exécute. Ainsi, lorsque le trap
la commande est exécutée en dehors du shell non interactif et dans le shell parent,
$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
le bash
non interactif , et sleep
les commandes n'hériteront pas de ce trap
du shell parent. Les gestionnaires de signaux sont perdus lors de l'exécution d'une commande différente (execve()
efface tout l'espace d'adressage du processus, y compris le code du gestionnaire). Sur execve()
, les signaux qui avaient un gestionnaire défini reviennent à la disposition par défaut, ceux qui ont été ignorés restent ignorés.
En plus de cela, dans la plupart des shells, trap
s sont également réinitialisés dans les sous-shells.
2.
Lorsque Bash attend une commande asynchrone via la commande intégrée wait , la réception d'un signal pour lequel un déroutement a été défini entraînera le retour immédiat de la commande interne d'attente avec un état de sortie supérieur à 128, immédiatement après lequel le déroutement est exécuté.
Lors de l'utilisation de wait
explicitement , wait
est interrompu par tout signal qui a un piège (et évidemment aussi ceux qui tuent complètement le shell).
Cela rend difficile l'obtention fiable de l'état de sortie d'une commande lorsqu'il y a des signaux piégés :
$ bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 10" & wait "$!"; echo "$?"'
^COuch
130
Dans ce cas, sleep
et sh
n'ont pas été tués par le SIGINT (puisqu'ils l'ignorent). Toujours wait
revient avec un 130
état de sortie car un signal (SIGINT) a été reçu alors qu'il attendait sh
. Vous devrez répéter le wait "$!"
jusqu'à sh
se termine vraiment pour obtenir sh
le statut de sortie.