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?
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