Can I assign a different exit status to a shell script in a trap handler?
Through trial-and-error, I found that calling exit
in trap
the exit status can be changed. Normal commands, whether fail or succeed, won't change the exit status.
Now I want to know, if I can rely on this behavior, or is it some implementation quirk?
I have been trying to find some doc on this, but to no avail.
Test script:
#!/bin/bash
function handler {
# a successful command won't change script exit status
echo handler, status=1ドル
# badcommand won't change script exit status
#badcommand
# exit will change script exit status
#exit 23
}
trap 'handler $?' EXIT
#badcommand
Usage:
./trap_test.sh; echo status_out=$?
2 Answers 2
I found that [by] calling
exit
in trap the exit status can be changed. Normal commands, whether fail or succeed, won't change the exit status. Now I want to know, if I can rely on this behavior, or is it some implementation quirk?
Yes you can rely on it, and it is documented, in the shell standard:
NAME
exit
- cause the shell to exit
...
DESCRIPTION
...
A trap onEXIT
shall be executed before the shell terminates, except when theexit
utility is invoked in that trap itself, in which case the shell shall exit immediately.
...
EXIT STATUS
The exit status shall ben
, if specified, except that the behavior is unspecified ifn
is not an unsigned decimal integer or is greater than255
. Otherwise, the value shall be the exit value of the last command executed, or zero if no command was executed. Whenexit
is executed in a trap action, the last command is considered to be the command that executed immediately preceding the trap action.
(same thing about return
)
And when there's no exit
command but an exit
trap was set, the following should apply:
Unless otherwise stated, the exit status of a command shall be that of the last simple command executed by the command.
and all the rules about compound commands, sequential lists, etc which make no special exception for the existence of an EXIT
trap.
-
1A caveat is needed in the case when
set -e
has been used in the script. For example, try this command with and without the-e
flag:bash -e -c "trap 'false' EXIT"; echo $?
. If-e
has been used, then the error code from thetrap
IS RETURNED to the caller. (I was surprised to discover this, since I agree with your interpretation of the shell standard.)superbatfish– superbatfish2023年10月06日 16:27:52 +00:00Commented Oct 6, 2023 at 16:27 -
@superbatfish using
-e
causes the shell to exit immediately if a command exits with a non-zero status, as you likely know. So your command with-e
could be rewritten without it, asbash -c "trap 'true; exit 1' EXIT"; echo $?
, and the behaviour is the same. So I think this is consistent with the above -- it can be seen as a case ofexit
being executed within the exit trap .SpinUp __ A Davis– SpinUp __ A Davis2024年06月12日 16:09:26 +00:00Commented Jun 12, 2024 at 16:09 -
Indeed, it looks like
set -e
has "precedence" overtrap ... EXIT
, can trigger TWICE and even abort the exit handler! This can be seen withset -x
like this:bash -e -xc 'retx() { return 1ドル;} ; hdlr() { retx 2; exit;} ; trap hdlr EXIT; retx 3; exit 4'; echo $?
(tested with bash version 5.2.37)MarcH– MarcH2024年12月04日 23:47:30 +00:00Commented Dec 4, 2024 at 23:47
I don't see the man page mentioning it, so other than looking at the code, experimentation seems like the best way of figuring out what happens.
It makes sense to me though that an EXIT trap wouldn't always change the exit status: a script might want to do some cleanup via the trap on exit, but not have that cleanup mess the exit status set by the main script. And, as you said, the trap can just run exit
again to set a desired value.
E.g. if you have this:
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT
# something
exit 1
the rm
would likely reset the exit status to zero, which doesn't seem that useful.
set -e
in your script, then errors in thetrap
will be returned to the caller. For example, try this command with and without the-e
part:bash -e -c "trap 'false' EXIT"; echo $?
The value of "$?" after the trap action completes shall be the value it had before the trap action was executed.