Keep exit codes when trapping SIGINT and similar?
Actually, interrupting bash's internal read
seems to be a bit different to interrupting a command run by bash. Normally, when you enter trap
, $?
is set and you can preserve it and exit with the same value:
trap 'rc=$?; echo $rc SIGINT; exit $rc' INT
trap 'rc=$?; echo $rc EXIT; exit $rc' EXIT
If your script is interrupted when executing a command like sleep
or even a builtin like wait
, you will see
130 SIGINT
130 EXIT
and the exit code is 130. However, for read -p
, it seems $?
is 0 (on my version of bash 4.3.42 anyway).
The handling of signals during read
might be work in progress, according to
the changes file in my release... (/usr/share/doc/bash/CHANGES)
changes between this version, bash-4.3-alpha, and the previous version, bash-4.2-release.
New Features in Bash
r. When in Posix mode, `read' is interruptible by a trapped signal. After running the trap handler, read returns 128+signal and throws away any partially-read input.
Any usual signal exit code will be available in $?
upon entry to the trap handler:
sig_handler() {
exit_status=$? # Eg 130 for SIGINT, 128 + (2 == SIGINT)
echo "Doing signal-specific up"
exit "$exit_status"
}
trap sig_handler INT HUP TERM QUIT
If there is a separate EXIT trap, you can use the same methodology: immediately keep the exit status passed from the signal handler (if there is one) clean-up, then return the saved exit status.
All you need to do is change the EXIT handler inside your cleanup handler. Here's an example:
#!/bin/bash
cleanup() {
echo trapped exit
trap 'exit 0' EXIT
}
trap cleanup EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. '