I have “trap 'echo ignore' USR1” in my cal

2019-08-09 08:49发布

问题:

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?

回答1:

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


回答2:

Try this change

/tmp/usr1er:

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

Handled TERM signal instead of EXIT & sent USR1 to $PPID instead of 0