Bash 4.3.22, HP-UX. imadev:~$ child() { trap - INT; trap 'echo I got an INT; trap - INT; kill -INT $ BASHPID' INT; while true; do sleep 1; done; }; child & [1] 19116 imadev:~$ kill -INT 19116 imadev:~$ kill -INT 19116 imadev:~$ kill -TERM 19116 [1]+ Terminated child
The manual says: Non-builtin commands run by bash have signal handlers set to the values inherited by the shell from its parent. When job control is not in effect, asynchronous commands ignore SIGINT and SIGQUIT in addition to these inherited handlers. And yes, turning on job control magically makes it work: imadev:~$ child() { set -m; trap - INT; trap 'echo I got an INT; trap - INT; kil l -INT $BASHPID' INT; while true; do sleep 1; done; }; child & [1] 19127 imadev:~$ kill -INT 19127 imadev:~$ I got an INT [1]+ Interrupt child But I don't understand why job control is needed to override an inherited (or automatically created) trap. Shouldn't an explicit trap always be used? Ksh (88) does not have this problem: imadev:~$ ksh $ child() { trap - INT; trap 'echo I got an INT; trap - INT; kill -INT $BASHPID' INT; while true; do sleep 1; done; }; child & [1] 19133 $ kill -INT 19133 $ I got an INT child: kill: bad argument count (Of course, ksh also doesn't have BASHPID, so ignore that last bit.)