trap
is a builtin of the shell that gives an interface to signal()
/ sigaction()
. The behaviour wrt external command in that regard is the same as in other languages where you change signal disposition.
When you execute another command by way of the execve()
system call, the memory of the process including the code, so including the code of signal handler is wiped to be replaced by that of the new executable, so there's no way signal handlers could survive.
POSIX says about execve()
:
Signals set to the default action (SIG_DFL
) in the calling process image shall be set to the default action in the new process image. Except for SIGCHLD
, signals set to be ignored (SIG_IGN
) by the calling process image shall be set to be ignored by the new process image. Signals set to be caught by the calling process image shall be set to the default action in the new process image (see <signal.h>
).
If the SIGCHLD
signal is set to be ignored by the calling process image, it is unspecified whether the SIGCHLD
signal is set to be ignored or to the default action in the new process image.
trap '' NAL
sets the SIG_IGN
disposition for the signal and trap - NAL
SIG_DFL
.
trap
has additional requirements (many of which could be seen as limitations and that some shell implementations ignore):
- while a process inherits signal handlers upon forking, in shells handlers are reset in subshells. For some signals, that's useful like the SIGINT/SIGQUIT/SIGHUP/SIGTSTP that are often sent to both parent and child, sometimes not.
- POSIX shells are forbidden to allow users to restore handlers for signals that were ignored upon start.
- some signals are automatically ignored in asynchronous commands.
- mingling with SIGCHLD is often not working as the shell does its own handling of it.
- I've always found signal handling in shell scripts to be unreliable and unportable in general.