11

I tried to have an interactive program in a bash script :

my_program

And I wish to be able to close it with 'Ctrl + c'. But when I do it my script is closing as well.

I know about.

trap '' 2
my_program
trap 2

But in this case, I just can't close my_program with Ctrl + c.

Do you have any idea how to allow Ctrl + c on a program, but not closing the script running it ?

EDIT : add example

#!/bin/bash
my_program
my_program2

If i use Ctrl + c to close my_program, my_program2 is never executed because the whole script is exited.

bob dylan
  • 1,862

3 Answers3

13

You should use trap true 2 or trap : 2 instead of trap '' 2. That's what "help trap" in a bash shell says about it:

If ARG is the null string each SIGNAL_SPEC is ignored by the shell and by the commands it invokes.

Example:

$ 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
12

You can reset a trap to its default by giving the trap command - as its action argument. If you do this in a subshell, it won't affect the trap in the parent shell. In your script, you can do this for each command that you need to be interruptible with 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
  • 25,413
  • 3
  • 64
  • 82
  • 1
    While the accepted answer is probably better and more canonical for shell, this is a great answer in itself in that it introduces the general principle (not shell-specific) for how to do this sort of signal masking/ignoring safely. – R.. GitHub STOP HELPING ICE Sep 10 '18 at 17:11
  • I guess you can exec my_program in the subshell, to be slightly more efficient. – Toby Speight Sep 10 '18 at 17:15
  • @R.. that's absolutely not shell specific -- if you set a signal to SIG_IGN (that's what trap with an empty string is doing), that state will be inherited through exec(), except for SIGCHLD. That's POSIX mandated behavior. See also the answer to https://stackoverflow.com/questions/32708086/ignoring-signals-in-parent-process –  Sep 10 '18 at 17:26
  • @mosvy: I don't see what part of my comment you're disagreeing with. My whole point was that "mask/ignore before fork, unmask/unignore in the child before exec" is a general principle that's useful to know outside the context of just shell programming. – R.. GitHub STOP HELPING ICE Sep 10 '18 at 17:30
  • @TobySpeight: Yes, exec would be preferable too. – R.. GitHub STOP HELPING ICE Sep 10 '18 at 17:30
  • 1
    This is a very useful answer. As an experienced Linux user, I can say I've never heard of this before. It has quite a lot of uses... you got my upvote and my bookmark. – Dev Sep 11 '18 at 04:37
-1


When you use Crtl+C, you interrupt the program ("kill" it).
What you are probably looking for is to suspend your program ("pause" it). For this, you can use Crtl+Z.
Once your program is paused, you can see it using jobs. For example:
[1]+ Stopped ./foobar
Here I only have one job, job #1, but there can be more than one - each job has its own number.
You can control you suspended process using a number of commands, for example bg, fg and kill.
bg %1 will restart job #1 in the background
fg %1 will restart job #1 in the foreground
kill %1 will kill job #1
Note that you can use bg and fg with no arguments if you only have one active job.

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
pi0tr
  • 318