12

Following is a shell script (myscript.sh) I have:

#!/bin/bash

sleep 500 &

Aprogram arg1 arg2  # Aprogram is a program which runs for an hour.

echo "done"

I launched this in one terminal, and from another terminal I issued 'kill -INT 12345'. 12345 is the pid of myscript.sh.

After a while I can see that both myscript.sh and Aprogram have been dead. However 'sleep 500 &' is still running.

Can anyone explain why is this behavior?

Also, when I issued SIGINT signal to the 'myscript.sh' what exactly is happening? Why is 'Aprogram' getting killed and why not 'sleep' ? How is the signal INT getting transmitted to it's child processes?

ernesto
  • 1,899
  • 4
  • 26
  • 39
  • What exactly is the intended purpose of `sleep 500 &` anyway? Seems to be a relatively useless waste of a process... – twalberg Apr 04 '14 at 18:20

3 Answers3

13

You need to use trap to catch signals:

To just ignore SIGINT use:

trap '' 2

if you want to specify some special action for this you can make it that in line:

trap 'some commands here' 2

or better wrap it into a function

function do_for_sigint() {
 ...
}

trap 'do_for_sigint' 2

and if you wish to allow your script to finish all it's tasks first:

keep_running="yes"

trap 'keep_running="no"' 2

while [ $keep_running=="yes" ]; do
 # main body of your script here
done
pawel7318
  • 3,383
  • 2
  • 28
  • 44
  • 1
    I understand that trap can be used. But I am looking for an explanation of this behavior. What will *shell* do when it receives SIGINT. For example look at this article http://mywiki.wooledge.org/SignalTrap#When_is_the_signal_handled.3F . It has some details but I am still not clear. – ernesto Apr 04 '14 at 07:00
  • When the parent dies than it's children are still running. It's normal behavior. You can see how it looks like with `pstree -aup` – pawel7318 Apr 04 '14 at 07:04
  • But here in this case, after myscript.sh recieved SIGINT, it waits for Aprogram to complete and then both of them die. But sleep continues to exist. One child is getting killed and the other one is not. It's a background process, but still myscript.sh is it's parent. – ernesto Apr 04 '14 at 07:07
  • @Jayesh: every process is child of its parent, except the init with pid 1 (to be honest even init has its parent `start_init` but this is a different story) – pawel7318 Apr 04 '14 at 07:26
  • I get into same problem as you. Then I found [this](http://stackoverflow.com/questions/2524937/how-to-send-a-signal-sigint-from-script-to-script-bash) – pawel7318 Apr 04 '14 at 08:07
9

You start sleep in the background. As such, it is not killed when you kill the script.

If you want to kill sleep too when the script is terminated, you'd need to trap it.

sleep 500 &
sid=($!)                   # Capture the PID of sleep
trap "kill ${sid[@]}" INT   # Define handler for SIGINT

Aprogram arg1 arg2 & # Aprogram is a program which runs for an hour.
sid+=($!)
echo "done"

Now sending SIGINT to your script would cause sleep to terminate as well.

devnull
  • 118,548
  • 33
  • 236
  • 227
  • Please see my comment above. I understand that trap works. But I am looking for an explanation why a background job is not getting killed and it looks like shell waits for Aprogram to complete when it receives SIGINT signal. Please see this: http://mywiki.wooledge.org/SignalTrap#When_is_the_signal_handled.3F – ernesto Apr 04 '14 at 07:02
  • @ernesto A background job is a _different_ process altogether. As such, specifying the PID of the script wouldn't delete it. Regarding the other question, what do you observe if you send `SIGINT` to a script that contains only the `Aprogram` command? – devnull Apr 04 '14 at 07:06
  • 1
    After sending SIGINT via 'kill -INT pid', myscript.sh still exists, and Aprogram also continues to print the output unless it really completed it's execution. Please note the method of killing, it's not Ctrl+c , it's with 'kill -INT pid'. This seems to have a different effect. – ernesto Apr 04 '14 at 07:10
  • @ernesto Yes, I understand that `SIGINT` is not `SIGKILL` or `SIGHUP`. You'd need to start the other process in the background too and capture it's PID to pass to `trap`. Refer to the update above. – devnull Apr 04 '14 at 07:22
  • I believe this is wrong. If you run Aprogram in the background, the script will simply go on and finish on its own, leaving Aprogram running until you kill it. – Martin Sep 21 '21 at 14:33
5

After a while I can see that both myscript.sh and Aprogram have been dead. However 'sleep 500 &' is still running.

As soon as Aprogram is finished myscript.sh prints "Done" and is also finised. sleep 500 gets process with PID 1 as a parent. That is it.

Can anyone explain why is this behavior?

SIGINT is not deliverd to Aprogram when myscript.sh gets it. Use strace to make sure that Aprogram does not receive a signal.

Also, when I issued SIGINT signal to the 'myscript.sh' what exactly is happening?

I first thought that it is the situation like when a user presses Ctrl-C and read this http://www.cons.org/cracauer/sigint.html. But it is not exactly the same situation. In your case shell received SIGINT but the child process didn't. However, shell had at that moment a child process and it did not do anything and kept waiting for a child. This is strace output on my computer after sending SIGINT to a shell script waiting for a child process:

>strace -p 30484
Process 30484 attached - interrupt to quit
wait4(-1, 0x7fffc0cd9abc, 0, NULL)      = ? ERESTARTSYS (To be restarted)
--- SIGINT (Interrupt) @ 0 (0) ---
rt_sigreturn(0x2)                       = -1 EINTR (Interrupted system call)
wait4(-1,

Why is 'Aprogram' getting killed and why not 'sleep' ? How is the signal INT getting transmitted to it's child processes?

As far as I can see with strace a child program like your Aprogram is not getting killed. It did not receive SIGINT and finished normally. As soon as it finished your shell script also finished.

  • Excellent explanation. Could you please also give some idea on why shell is treating background process as different? I mean, shell waits for Aprogram to complete, but won't wait for sleep. Why is this behavior? – ernesto Apr 04 '14 at 09:56
  • 1
    `shell waits for Aprogram to complete, but won't wait for sleep`. Well, it is because of `&` that you have added after `sleep`. Please read https://en.wikipedia.org/wiki/Background_process#Launch_.26_resumption_on_Unix. –  Apr 04 '14 at 10:17
  • And for completeness, if the `kill` used a `-` in front of the pid like `kill -INT -12345` this would send the signal to the process group of the shell script, which *would* probably terminate `Aprogram`. – Steven Lu Feb 04 '20 at 22:26