bashprocessprocess-group

I have "trap 'echo ignore' USR1" in my called script, why does the calling script get killed?


Say I have these two bash scripts:

/tmp/trapper:

#!/bin/bash
trap 'echo trapper: ignoring USR1' USR1
"$(dirname $0)"/usr1er & p=$!
sleep 1
echo trapper: now killing usr1er
kill $p
echo trapper: sleeping
sleep 1
echo trapper: reached end of trapper

/tmp/usr1er:

#!/bin/bash
trap 'echo "usr1er: EXIT received, sending USR1"; kill -USR1 0' EXIT
while sleep 1;do echo usr1er: sleeping;done

trapper is supposed to trap USR1 and simply ignore it. It starts usr1er, which kills its process group with the USR1 signal. Now, if I start trapper as a script on its own from an interactive shell, it kills usr1er and exits normally:

$ /tmp/trapper; echo done
trapper: now killing usr1er
trapper: sleeping
usr1er: EXIT received, sending USR1
/tmp/trapper: line 9: 16596 Terminated              "$(dirname $0)"/usr1er
trapper: ignoring USR1
trapper: reached end of trapper
done

While if I try $(/tmp/trapper), it exits the whole shell. Similarly, if I make a separate script that calls /tmp/trapper, like /tmp/outer:

#!/bin/bash
"$(dirname $0)"/trapper
echo outer: reached end of outer

it gets killed without printing the "reached end of outer":

$ /tmp/outer
trapper: now killing usr1er
trapper: sleeping
usr1er: EXIT received, sending USR1
User defined signal 1
/tmp/trapper: line 9: 23544 Terminated              "$(dirname $0)"/usr1er
User defined signal 1
trapper: ignoring USR1
trapper: reached end of trapper

Why?


Solution

  • It seems that $() does not start the process with a separate process group / PGID (apparantly for making C-c work).

    Also, any non-interactive shell will also not start separate PGID's for their children (unless you turn on job control with set -m):

    $ bash -c '/tmp/trapper;echo done'
    trapper: now killing usr1er
    trapper: sleeping
    usr1er: EXIT received, sending USR1
    User defined signal 1
    $ /tmp/trapper: line 9: 17522 Terminated              "$(dirname $0)"/usr1er
    trapper: ignoring USR1
    trapper: reached end of trapper
    

    Note that "done" is not printed, the outer bash script, which doesn't trap USR1, is killed while trapper keeps on living until the end.

    You can check the PGID of each process by putting ps -o %p%r%c -p$$ in the scripts:

    $ /tmp/outer
      PID  PGID COMMAND
    27630 27630 outer
      PID  PGID COMMAND
    27633 27630 trapper
      PID  PGID COMMAND
    27635 27630 usr1er
    trapper: now killing usr1er
    trapper: sleeping
    usr1er: EXIT received, sending USR1
    User defined signal 1
    $ /tmp/trapper: line 9: 27635 Terminated              "$(dirname $0)"/usr1er
    trapper: ignoring USR1
    trapper: reached end of trapper