When trapping a signal in a shell script, the trap commands are not executed until the current command finishes. For example, consider the following shell script:
#!/bin/bash trap 'echo "SIGTERM caught"' SIGTERM i=0 while : ; do echo "$((++i))" timeout 10 yes >/dev/null done
If one runs this script and then tries to send SIGTERM to the process, the echo statement in the trap function does not run until completion of the active command.
By backgrounding a command and using wait, signals can be handled during command execution, e.g.,
#!/bin/bash trap 'echo "SIGTERM caught"; [[ "$pid" ]] && echo "Killing $pid" && kill "$pid"' SIGTERM i=0 while : ; do echo "$((++i))" timeout 10 yes >/dev/null & pid=$! wait done
However, while SIGTERM is now caught immediately, this causes the process to respond incorrectly to other signals like SIGINT. For instance, if the above script is run, it cannot be terminated by SIGINT if SIGTERM was sent more than a few moments earlier. For instance, if
$pid is the process ID of the shell script, either of the following will kill the process (in the latter case, the process is interrupted by SIGINT before it has a chance to respond to SIGTERM):
kill -SIGINT "$pid" kill "$pid"; kill -SIGINT "$pid"
whereas the following will not (the process hangs and must be killed by delivering SIGKILL):
kill "$pid"; sleep 0.01; kill -SIGINT "$pid" SIGTERM caught # process hangs at this point
What changes need to be made to the trap to avoid improper handling of other signals?