"When do bash
signal handlers NOT work?"
March 19th, 2019
Just in case somebody else runs into this frustrating situation, (at least on RHEL 7) bash
shell scripts trying to catch SIGINT
do not work when the signal is sent to the process from another pid and your bash script is running a non-shell built-in.
Yesterday I was attempting to mock out a linux command to verify the behavior of a shell script I wrote. The goal was to be able to test the shell script's behavior without actually invoking the particular linux command (see pbench PR #1108). One feature of the script being tested was sending a SIGINT
to another process, being sure the script had properly identified the correct process.
There is a nice blog about how to write signal handlers for bash, well worth the read [1]. Using that blog, I came up with a very simple mock command shell script:
#!/bin/bash
printf -- "$0 $@\n"
sighand() {
printf -- "$0: sig handled\n" >&2
exit 0
}
trap sighand SIGINT
sleep 9999
printf -- "$0: done\n"
exit 0
The above script works fine if you run from a shell, and in the same shell you type Ctrl-C
. But if you try to send SIGINT
from another process, the sleep 9999
is not interrupted.
If instead we place the sleep 9999
in the background and wait for it with the wait
built-in, both sending the signal from the same shell via Ctrl-C
and from a remote process works just fine:
#!/bin/bash
printf -- "$0 $@\n"
sighand() {
printf -- "$0: sig handled\n" >&2
exit 0
}
trap sighand SIGINT
sleep 9999 &
wait
printf -- "$0: done\n"
exit 0
The reason for this behavior is that the bash parent shell of the command has SIGINT
and other signals blocked when executing sleep 9999
which is NOT a built in function of bash. But since wait
is a built-in function signals are handled as expected (see the answer to [2] for more information).
[1]: http://linuxcommand.org/lc3_wss0150.php
[2]: https://stackoverflow.com/questions/2524937/how-to-send-a-signal-sigint-from-script-to-script-bash
From Doran:
Good observations, but a couple of points of feedback:
/bin/sleep
subprocess in the background. Best to clean up subprocesses when you exit due to a signal with something like: