Bash – Difference between ‘trap -⁠- EXIT’ and ‘trap – EXIT’

bashexitshelltrap:

I've noticed that when Bash is called as sh, you cannot unset a trap using e.g., trap -- EXIT, but when it is called as bash you can.

trap - EXIT seems to work regardless of how the shell was called.


Example output:

[vagrant@localhost ~]$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar  9  2016 /bin/sh -> bash
[vagrant@localhost ~]$ sh
sh-4.1$ trap 'echo something' EXIT
sh-4.1$ exit
exit
something
[vagrant@localhost ~]$ sh
sh-4.1$ trap 'echo something' EXIT
sh-4.1$ trap -- EXIT
trap: usage: trap [-lp] [[arg] signal_spec ...]
sh-4.1$ trap - EXIT
sh-4.1$ exit
exit
[vagrant@localhost ~]$ bash
[vagrant@localhost ~]$ trap 'echo something' EXIT
[vagrant@localhost ~]$ exit
exit
something
[vagrant@localhost ~]$ bash
[vagrant@localhost ~]$ trap 'echo something' EXIT
[vagrant@localhost ~]$ trap -- EXIT
[vagrant@localhost ~]$ exit
exit
[vagrant@localhost ~]$ bash
[vagrant@localhost ~]$ trap 'echo something' EXIT
[vagrant@localhost ~]$ trap - EXIT
[vagrant@localhost ~]$ exit
exit
[vagrant@localhost ~]$ 

I checked the documentation but I don't see the difference elucidated anywhere. I do see that the single hyphen form is specified by POSIX.

Is there any difference in behavior between the two methods of unsetting a trap, other than -- not working in sh?

Best Answer

This is explained some in the trap(1P) man page and more in the Advanced Bash Scripting Guide, which explains that the -- is a Bash built-in, used to denote the "end of options" for a command. Since scripts using sh are designed to be portable between other systems with it, bash behaves as if it were executed with --posix, which changes some shell behavior to match the POSIX specification.

When a signal is "trapped", (e.g., EXIT), it binds the first argument after the command to the signal, eval-ing it when the signal is issued, and ignoring its normal behavior (except for EXIT). So when trap 'echo something' EXIT is run, then exit, the shell will eval 'echo something' prior to exiting. This would also work with a different signal, such as TERM, which could be bound to, for example, a graceful exit function in a script. When trap -- EXIT is run, the -- is interpreted as an "end of arguments", indicating to trap that the signal is to be bound to null ('') (since there were no flags prior to or after --), indicating to the shell to ignore the signal (however, this doesn't work with EXIT, but works with other signals). Running trap -- 'echo something' EXIT, however, will still eval 'echo something' and exit upon exit. As per the specification of trap, the command - by itself indicates that the shell will reset any traps for the signals specified, which is why it works in both sh and Bash.

Related Question