GNU/Linux >> Tutoriels Linux >  >> Linux

Lorsque vous tapez Ctrl-c dans un terminal, pourquoi le travail de premier plan n'est-il pas terminé jusqu'à ce qu'il soit terminé ? ?

Fermé . Cette question a besoin de détails ou de clarté. Il n'accepte pas de réponses actuellement.

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 :

  1. 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 signal SIGINT , le piège du signal
    SIGINT , lorsqu'il est défini, sera exécuté jusqu'à ce que la commande se termine ?
    Si oui, pourquoi dans mon premier exemple, est-ce que ctrl-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
    
  2. Que signifie "un signal pour lequel un piège a été tendu" veux dire,

    • un signal arg dont le trap a été spécifié via trap 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 ?

  3. J'ai mis en place un piège pour SIGINT , mais ctrl-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
    
  4. 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.

En relation:Linux - Augmenter le volume d'une vidéo MKV à partir d'un terminal Linux ?

(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).

Connexe :Comment formater rapidement une partition dans un système de fichiers ?

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.


Linux
  1. Pourquoi l'invite Bash est-elle boguée lorsque je parcours l'historique ? ?

  2. Pourquoi (et comment) l'utilisation de Cat sur des fichiers binaires a-t-elle gâché le terminal ?

  3. Lors de l'utilisation de Vlc, pourquoi l'économiseur d'écran continue-t-il de se réveiller ?

  4. Pourquoi le service persistant Iptables n'enregistre-t-il pas les modifications ?

  5. Pourquoi le curseur saute-t-il lors de la frappe ?

Pourquoi j'aime toujours Alpine pour le courrier électronique sur le terminal Linux

Bash-insulter - Un script qui insulte l'utilisateur lorsqu'il tape une mauvaise commande

Quand un signal est-il traité et pourquoi certaines informations se bloquent-elles ?

pourquoi une boucle bash while ne se termine-t-elle pas lorsqu'elle est dirigée vers une sous-commande terminée?

Pourquoi ne puis-je pas faire défiler dans le terminal ?

Quand le système envoie-t-il un SIGTERM à un processus ?