Comment faire ctrl + c / pas / interrompre la boucle while?

11

Étant donné cette boucle:

while sleep 10s ; do
  something-that-runs-forever
done

Lorsque j'appuie sur Ctrl + C, toute la boucle while est interrompue. Ce que je veux faire, c'est interrompre le processus "quelque chose", laisser passer 10 secondes, puis redémarrer "quelque chose".

Comment puis-je faire en sorte que ctrl + c n'affecte que "quelque chose", et non la boucle while?

EDIT: "interrompre" comme dans SIGINT. Tuer. Avorter. Mettre fin. Pas "interrompre" comme dans "pause".

bos
la source
Si vous voulez simplement le suspendre, pourquoi ne pas utiliser Ctrl + Z, attendre 10 secondes et exécuter fg? Pourquoi utiliser Ctrl + C?
terdon
@terdon: Merci pour le commentaire, peut-être que je me suis précipité avec la réponse. Besoin de lire plus sur les exigences des PO
Inian
@terdon: Je ne veux pas l'interrompre. Je veux que 10 secondes passent, comme je l'ai écrit.
bos
Vous avez dit: What I want to do is to interrupt the "something"-process, let 10 seconds pass, and then restart "something". Si vous appuyez sur Ctrl + Z, attendez 10 secondes, puis exécutez fg, c'est exactement ce qui se passera. Peut-être pourriez-vous modifier votre question et donner un exemple spécifique afin que nous puissions mieux comprendre?
terdon
3
Je pensais que dans le contexte de l'interruption Ctrl + C était sans ambiguïté, mais évidemment j'avais tort. J'ai maintenant édité.
bos

Réponses:

18

Cela devrait fonctionner si vous venez trap SIGINTde quelque chose. Comme :( true).

#!/bin/sh
trap ":" INT    
while sleep 10s ; do
    something-that-runs-forever
done

Interrompre le something...ne fait pas quitter le shell maintenant, car il ignore le signal. Cependant, si vous ^ C le sleepprocessus, il se terminera avec un échec, et la boucle s'arrête à cause de cela. Déplacez le sleepà l'intérieur de la boucle ou ajoutez quelque chose comme || truepour éviter cela.

Notez que si vous utilisez trap "" INTpour ignorer complètement le signal (au lieu de lui affecter une commande), il est également ignoré dans le processus enfant, vous ne pouvez donc pas interrompre non something...plus. Ceci est explicitement mentionné dans au moins le manuel de Bash :

Si arg est la chaîne nulle, le signal spécifié par chaque sigspec est ignoré par le shell et les commandes qu'il invoque. [...] Les signaux ignorés lors de l'entrée dans le shell ne peuvent pas être capturés ou réinitialisés.

ilkkachu
la source
Cela peut-il également être réalisé dans le shell actuel? (Pas dans un script.)
1
Vous souhaiterez peut- do (trap - INT; something-that-runs-forever)être autoriser l'interruption de la commande. En outre, vous n'avez pas besoin de courir :- vous pouvez simplement utiliser une chaîne vide pour ignorer un signal: trap '' INT. Tout cela est POSIX, et devrait fonctionner sur n'importe quel shell compatible (pas seulement Bash).
Toby Speight du
Notez également que l'écriture SIGINTcomplète n'est pas strictement portable: "Les implémentations peuvent autoriser les noms avec le SIGpréfixe ou ignorer la casse dans les noms de signaux comme une extension . " (C'est moi qui souligne)
Toby Speight
vous pouvez passer la chaîne vide comme action pour ignorer un signal, par exemple trap "" INT(également posix)
daf
@TobySpeight, la raison pour laquelle j'ai utilisé à la trap :place trap ""était exactement cela, pour ne pas ignorer le signal (mais en faire un no-op à la place), afin que nous n'ayons pas besoin de faire autre chose pour pouvoir interrompre le somethingprogramme principal .
ilkkachu
0

Une autre option consiste à faire something-that-runs-forevergérer le signal (en quittant avec élégance quand il est reçu). Bien sûr, cela n'a de sens que lorsque ce programme est utilisé dans de nombreux scripts, et que le comportement souhaité sur CTRL+ Cest systématiquement le même - pour continuer l'exécution du script.

Dmitry Grigoryev
la source
ITYM "s'endort et se ré-exécute", pas "se termine gracieusement"?
Toby Speight