I have a program which is supposed to handle SIGINT and gracefully shut down. When I run this program from a terminal without backgrounding it I can shut it down just fine using Ctrl-C. Inspecting the logs shows that everything worked as expected.

When I open a separate terminal and call kill -2 [pid] or kill -s INT [pid] it does nothing. I see nothing in the logs and the program continues to run as usual until I hit Ctrl-C in the terminal I launched it from.

Are there any differences between how Ctrl-C sends the signal and how kill does?

Additional Details:

The program in question is a Java application launched by a bash shell script which sets up some environment variables (namely CLASSPATH) and then calls java [main class]. Hitting Ctrl-Z and then running ps results in the following:

$ ps -f
mdeck    10251 10250  0 11:48 pts/2    00:00:00 -bash
mdeck    13405 10251  0 18:12 pts/2    00:00:00 /bin/bash /usr/local/bin/myapp.sh
mdeck    13509 13405 25 18:12 pts/2    00:00:03 java com.company.MyApp
mdeck    13526 10251  0 18:13 pts/2    00:00:00 ps -f

The output of stty as requested by Gilles is below:

$ stty -a </dev/pts/2
speed 38400 baud; rows 40; columns 203; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
  • 2
    Does the program run in a single process? Does the program capture Ctrl+C instead of reacting to a signal? What is the output of stty -a </dev/pts/42 where /dev/pts/42 is the output of tty in the terminal where you start the process? Commented Aug 13, 2012 at 22:49
  • @Gilles, I've updated the question to include some of the information you're requesting.
    – Mike Deck
    Commented Aug 13, 2012 at 23:16

2 Answers 2


One possibility is that the program catches the Ctrl+C sequence. Check the output of stty -a; the intr setting indicates which key combination (if any) sends a SIGINT signal, and the isig indicates whether the signal keys are enabled (-isig means they are disabled).

If the program consists of several processes, pressing Ctrl+C sends SIGINT to all the processes in the process group. You can obtain the same effect by sending the signal to the process group instead of sending it to one of the processes. To send a signal to a process group, first determine its leader: that's the first process that starts all the others; if you run the process group in the background, that's the PID shown by jobs -l. The PID of the process group leader is the PGID (process group id); send the signal to its negative. E.g. if the PGID is 1234, run kill -INT -1234.

If the program consists of a wrapper script and a main application, there are two cases to consider. If there is no cleanup to do, so that the wrapper script terminates as soon as the main aplication terminates, make the wrapper script call exec:

export SOMEVAR=somevalue
exec /path/to/application "$@"

This way the application replaces the script, inheriting its PID. Some shells optimize a script that ends by executing another program, but not all. This approach doesn't work when the script needs to perform some cleanup such as removing temporary files.

Consider making the script detect a signal and transmitting the signal to the application. Here's a sketch of how this goes:

/path/to/application "$@" &
trap -INT 'kill -INT $app_pid'
wait $!
rm /temp/file

Based on the questions @Gilles asked in the comments to my original question I realized that the kill -2 command I was sending was targeting the pid of the wrapper script which launched the application instead of the process which handles the signal itself.

Using the pids from my question, kill -s 13405 was not properly signaling the application, but calling kill -s 13509 works as expected.

Now my question is how can I update my wrapper script to propagate a SIGINT to its child processes, but I'll create a separate question for that.

  • 7
    To perfectly match the behavior of the tty interrupt character, you should send the SIGINT to the process group. Instead of kill -2 $PID use kill -2 -$PGID. (The minus in front of the PGID tells kill to interpret it as a PGID instead of a PID). You can find the PGID with ps j. The PGID is the same as the lead process's PID so your command probably ends up looking the same except for the -.
    – Alan Curry
    Commented Aug 13, 2012 at 23:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .