Shell – Keep exit codes when trapping SIGINT and similar

exitshellshell-scriptsignalstrap:

If I use trap like described e.g. on http://linuxcommand.org/wss0160.php#trap to catch ctrl-c (or similar) and cleanup before exiting then I am changing the exit code returned.

Now this probably won't make difference in the real world (e.g. because the exit codes are not portable and on top of that not always unambiguous as discussed in Default exit code when process is terminated?) but still I am wondering whether there there is really no way to prevent that and return the default error code for interrupted scripts instead?

Example (in bash, but my question shouldn't be considered bash-specific):

#!/bin/bash
trap 'echo EXIT;' EXIT
read -p 'If you ctrl-c me now my return code will be the default for SIGTERM. ' _
trap 'echo SIGINT; exit 1;' INT
read -p 'If you ctrl-c me now my return code will be 1. ' _

Output:

$ ./test.sh # doing ctrl-c for 1st read
If you ctrl-c me now my return code will be the default for SIGTERM.
$ echo $?
130
$ ./test.sh # doing ctrl-c for 2nd read
If you ctrl-c me now my return code will be the default for SIGTERM.
If you ctrl-c me now my return code will be 1. SIGINT 
EXIT
$ echo $?
1

(Edited to remove to make it more POSIX-conform.)

(Edited again to make it a bash script instead, my question is not shell-specific though.)

Edited to use the portable "INT" for trap in favor of the non-portable "SIGINT".

Edited to remove useless curly braces and add potential solution.

Update:

I solved it now by simply exiting with some error codes hardcoded and trapping EXIT. This might be problematic on certain systems because the error code might differ or the EXIT trap not possible but in my case it's OK enough.

trap cleanup EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM

Best Answer

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. '
Related Question