Consider the following minimal/arbitrary Bash script, which just slowly writes dots to stdout, until CTRLC is sent...
ctrlc.sh#!/usr/bin/env bash
declare -i have_ctrlc=0
function handler() {
printf 'SIGINT received\n'
have_ctrlc=1
}
trap handler SIGINT
while [[ "$have_ctrlc" -eq 0 ]]; do
printf '...'
sleep 1
done
printf 'Done\n'
This script works as advertised interactively -- dots are written until CTRLC is pressed, then SIGINT received
is printed, then Done
is printed.
Now consider the following "wrapper" script, which itself calls ./ctrlc.sh
with an arbitrary set of arguments and tees the output to a file...
#!/usr/bin/env bash
./ctrlc.sh with these arbitrary args | tee -a "${0}.out"
When this script is run, dots are printed, but pressing CTRLC aborts the child script before SIGINT received
and Done
are printed, and I can't seem to find any way to get those to print.
I have tried:
Changing the wrapper to invoke ctrlc.sh as a background job and waiting on that:
./ctrlc.sh with these arbitrary args | tee -a "${0}.out" & wait
In this form, CTRLC ends the wrapper, but the dots continue to print in the background I manually/explicitly
pkill -f ctrlc
the child process.Changing the wrapper to invoke ctrlc.sh as a background job, but having the wrapper trap CTRLC itself/as well, and send SIGINT onto the child (process substitution is used so I can get the PID of ctrlc.sh instead of tee):
./ctrlc.sh with these args > >(tee -a "${0}.out") & trap "kill -INT '$!' && printf 'Killed %s\n' '$!'" SIGINT wait
Changing ctrlc.sh to trap SIGUSR1 or SIGHUP, and changing the wrapper to send either of those onto the background job:
trap handler SIGHUP
./ctrlc.sh with these args > >(tee -a "${0}.out") & trap "kill -HUP '$!' && printf 'Killed %s\n' '$!'" SIGINT wait
Both #2 and #3 behave the same way: when CTRLC is pressed, the Killed 12345
message from wrapper.sh is shown and the dots stop printing, but the SIGINT received
and Done
from the child ctrlc.sh are still not shown.
What should I be doing instead?
For the avoidance of doubt, I need the while loop to be abortable (e.g. with CTRLC), and the actions after the while to be run as well. With minimal changes to the child ctrlc.sh script (the real script is much more complex than the minimal version).
(Bash version happens to be v4.3.33, which I appreciate is very old)
.out
file? Considering sending the SIGINT received message to stderr if isn't supposed to be part of the "product output".