Please explain this:
#!/bin/bash
# This is scripta.sh
./scriptb.sh &
pid=$!
echo $pid started
sleep 3
while true
do
kill -SIGINT $pid
echo scripta.sh $$
sleep 3
done
–
#!/bin/bash
# This is scriptb.sh
trap "echo Ouch;" SIGINT
while true
do
echo scriptb.sh $$
sleep 1
done
When I run ./scripta.sh
the trap doesn't print. If I switch from SIGINT to any other signal (I tried SIGTERM, SIGUSR1) the trap prints "Ouch" as expected. How can this happen?
Best Answer
Apparently you didn’t try SIGQUIT; you will probably find that it behaves the same as SIGINT.
The problem is job control.
In the early days of Unix, whenever the shell put a process or pipeline into the background, it set those processes to ignore SIGINT and SIGQUIT, so they would not be terminated if the user subsequently typed Ctrl+C (interrupt) or Ctrl+\ (quit) to a foreground task. When job control came along, it brought process groups along with it, and so now all the shell needs to do is put the background job into a new process group; as long as that is not the current terminal process group, the processes will not see signals coming from the keyboard (Ctrl+C, Ctrl+\ and Ctrl+Z (SIGTSTP)). The shell can leave background processes with the default signal disposition. In fact, it probably has to, for the processes to be killable by Ctrl+C when they are brought into the foreground.
But non-interactive shells don’t use job control. It makes sense that a non-interactive shell would fall back to the old behavior of ignoring SIGINT and SIGQUIT for background processes, for the historical reason — to allow the background processes to continue to run, even if keyboard-type signals are sent to them. And shell scripts run in non-interactive shells.
And, if you look at the last paragraph under the
trap
command in bash(1), you’ll seeSo, if you run
./scriptb.sh &
from your interactive shell’s command prompt, its signal dispositions are left alone (even though it’s being put into the background), and thetrap
command works as expected. But, if you run./scripta.sh
(with or without&
), it runs the script in a non-interactive shell. And when that non-interactive shell runs./scriptb.sh &
, it sets thescriptb
process to ignore interrupt and quit. And therefore thetrap
command inscriptb.sh
silently fails.