Piège 'Ctrl + c' pour le script bash mais pas pour le processus ouvert dans ce script

11

J'ai essayé d'avoir un programme interactif dans un script bash:

my_program

Et je souhaite pouvoir le fermer avec 'Ctrl + c'. Mais quand je le fais, mon script se ferme également.

Je sais.

trap '' 2
my_program
trap 2

Mais dans ce cas, je ne peux pas fermer my_programavec Ctrl + c.

Avez-vous une idée de comment autoriser Ctrl + c sur un programme, sans fermer le script qui l'exécute?

EDIT: ajouter un exemple

#!/bin/bash
my_program
my_program2

Si j'utilise Ctrl + c pour fermer my_program, il my_program2n'est jamais exécuté car le script entier est fermé.

Bob Dylan
la source

Réponses:

13

Vous devez utiliser trap true 2ou trap : 2au lieu de trap '' 2. C'est ce que "help trap" dans un shell bash en dit:

Si ARG est la chaîne nulle, chaque SIGNAL_SPEC est ignoré par le shell et par les commandes qu'il appelle .

Exemple:

$ cat /tmp/test
#! /bin/sh
trap : INT
cat
echo first cat killed
cat
echo second cat killed
echo done
$ /tmp/test
   <press control-C>
^Cfirst cat killed
   <press control-C>
^Csecond cat killed
done
mosvy
la source
2
Que diriez-vous de tuer tails au lieu de tuer des chats la prochaine fois?
kubanczyk
12

Vous pouvez réinitialiser un trap à sa valeur par défaut en donnant la commande trap -comme argument d'action. Si vous le faites dans un sous - shell , cela n'affectera pas le piège dans le shell parent. Dans votre script, vous pouvez le faire pour chaque commande dont vous avez besoin pour être interruptible avec Ctrl-C:

#!/bin/bash
# make the shell (and its children) ignore SIGINT
trap '' INT
.
.
.
# but this child won't ignore SIGINT
(trap - INT; my_program)
# the rest of the script is still ignoring SIGINT
.
.
.
Mark Plotnick
la source
1
Bien que la réponse acceptée soit probablement meilleure et plus canonique pour le shell, c'est une excellente réponse en soi, car elle introduit le principe général (non spécifique au shell) pour savoir comment faire ce type de masquage / ignorement de signal en toute sécurité.
R .. GitHub STOP HELPING ICE
Je suppose que vous pouvez exec my_programdans le sous-shell, être légèrement plus efficace.
Toby Speight du
@R .. ce n'est absolument pas spécifique au shell - si vous définissez un signal sur SIG_IGN (c'est ce que fait le trap avec une chaîne vide), cet état sera hérité via exec (), à l'exception de SIGCHLD. C'est un comportement mandaté par POSIX. Voir aussi la réponse à stackoverflow.com/questions/32708086/…
mosvy
@mosvy: Je ne vois pas avec quelle partie de mon commentaire vous n'êtes pas d'accord. Tout mon argument était que "masquer / ignorer avant fork, démasquer / ignorer chez l'enfant avant exec" est un principe général qu'il est utile de connaître en dehors du contexte de la simple programmation shell.
R .. GitHub STOP HELPING ICE
1
Ceci est une réponse très utile. En tant qu'utilisateur Linux expérimenté, je peux dire que je n'en ai jamais entendu parler auparavant. Il a beaucoup d'utilisations ... vous avez obtenu mon vote positif et mon signet.
Dev
-1


Lorsque vous utilisez Crtl+ C, vous interrompez le programme ("le tuez ").
Ce que vous cherchez probablement, c'est de suspendre votre programme (" pause "). Pour cela, vous pouvez utiliser Crtl+ Z.
Une fois votre programme en pause, vous pouvez le voir en utilisant jobs. Par exemple:
[1]+ Stopped ./foobar
Ici, je n'ai qu'un seul travail, le travail n ° 1, mais il peut y en avoir plusieurs - chaque travail a son propre numéro.
Vous pouvez contrôler votre processus suspendu à l'aide d'un certain nombre de commandes, par exemple bg, fget kill.
bg %1redémarrera le travail n ° 1 dans le cycle b ack g
fg %1 redémarrera le travail n ° 1 dans le f oreg round
kill %1tuera le travail # 1
Notez que vous pouvez utiliser bget fgsans argument si vous n'avez qu'un seul travail actif.

pi0tr
la source
Merci mais non, je souhaite faire Ctrl + c.
bob dylan