sleep, wait and Ctrl+C propagation
tl;dr; the Xvfb
process sets a signal handler for SIGINT
and exits when it receives such a signal, but the sleep
process doesn't, so it inherits the "ignore" state for SIGINT
as it was set by the shell running the script before executing the sleep
binary.
When a shell script is run, the job control is turned off, and background processes (the ones started with &
) are simply run in the same process group, with SIGINT
and SIGQUIT
set to SIG_IGN
(ignored) and with their stdin redirected from /dev/null
.
This is required by the standard:
If job control is disabled (see the description of set -m) when the shell executes an asynchronous list, the commands in the list shall inherit from the shell a signal action of ignored (SIG_IGN) for the SIGINT and SIGQUIT signals.
If the signal disposition is set to SIG_IGN
(ignore), that state will be inherited through fork()
and 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.
From the bash man page:
Background processes are those whose process group ID differs from the terminal’s; such processes are immune to keyboard-generated signals
You could handle this in different ways; first, to kill the listed jobs:
#!/bin/bash
trap 'kill $(jobs -p)' INT
sleep 30s &
wait
Alternatively, send a kill to all of the processes in the same process group:
#!/bin/bash
trap 'kill 0' INT
sleep 30s &
wait