Also, zsh has a much nicer mechanism for the common case:
{
echo lol
} always {
# Ensure *all* temporary files are cleaned up.
nohup rm -rf / &
}Also, zsh has a much nicer mechanism for the common case:
{
echo lol
} always {
# Ensure *all* temporary files are cleaned up.
nohup rm -rf / &
}You can examine $? on entry to the trap function. On signals, it will be 128 + signal. i.e. on TERM (15) it will be 143. On INT (2) it will be 130.
#!/bin/bash
skip_exit=
on_exit() {
code=$?
if test $code == 130; then
skip_exit=1
fi
if test -n "$skip_exit"; then
return
fi
echo "Exiting with: $code"
return $code
}
trap on_exit INT EXIT
sleep 2
false
With ctrl-c: $ ./foo.sh
^C
After 2 seconds: $ ./foo.sh
Exiting with: 1
You can also setup separate handlers for each signal and use a sentinel: $ cat foo.sh
#!/bin/bash
skip_exit=
on_int() {
echo int
skip_exit=1
}
on_exit() {
test -n "$skip_exit" && return
echo exit
}
trap on_int INT
trap on_exit EXIT
sleep 2
With ctrl-c: $ ./foo.sh
^Cint
After 2 seconds:
$ ./foo.sh
exitThis changes things again. Often a process started by the shell will get the signal, too (depends of course on how it is sent) and exit with a non-zero return value (depends on the process of course). I believe (not at the computer right now) the handler for EXIT is called in that case.
Was it so that bash can also trap ERR, but dash cannot?
It's not perfectly easy to handle all possible cases, and certainly impossible in a fully portable way.
Highly debatable.
We use an exit handler that reports
"$0 has exited prematurely"
in cases the script did not reach expected exit points.Of course in special cases where you do explicit error handling you can disable it. But for the big mass of commands where nobody checks whether it worked.
> The behavior of set -e is quite unpredictable. If you choose to use it, you will have to be hyper-aware of all the false positives that can cause it to trigger, and work around them by "marking" every line that's allowed to fail with something like ||true.
Start there, then go back to the beginning for the extensive exposition against using set -e.
FWIW, I (a random person on the internet) use set -e for most scripts I write, and despite the caveats, find set -e is generally more beneficial than troublesome. I don't think Mr. Wooledge is wrong, it's just the groove I've settled in. I do sometimes consciously avoid using set -e, when I explicitly handle errors for every single element of the script.
I do not doubt that may bash scripters shoot themselves in the foot. You need at least one reviewer that understands well how the language works.
That said I prefer dash for scripting except when I really need arrays, which is rare. I have no scientific evidence, but KISS is good and bash just seems to have too many bells and whistles. And as the article mentions, bash seems to change in surprising ways between versions. I have also been bitten by that. Unfortunately dash has no set -o pipefail.
It took a few seconds before I thought... "Why does it take that long for only a handful of files?"
I never did that again.
Had my DOS filesystem mounted under Linux too (yes that long ago), and I spent a few days guessing the first letter of each deleted file with norton disk doctor or undeleter or something. That was fun (FAT16 filesystems overwrote the first letter of each filename to delete it)
At least it wasn't a mistake I made at work on some production thing. Though there is a reason I make all the desktops on windows production servers bright red. One time I was tired and shut down "my laptop" forgetting I was still logged into a remote server 200km away..... :/ Of course the iLO wasn't hooked up but I was extremely happy to find that HP servers listen to wake on LAN even when they're off. Another one for the never again books :P
with UNIX/POSIX systems it pays to say "it depends" often.
There's this idea that macOS is "based on BSD", but that's not really the case in any meaningful way; it took some components, but the system overall isn't really "based on it" as such.
That said, it makes sense that at least some distros would leave a job in place to do so but initially disabled so that the user can decide based on the use-case
how about you?
Regarding the expected behaviour: I believe this is largely a matter of preference/philosophy. I have previously used trap handlers in bash scripts explicitly so that the cleanup is run in every case and /tmp is not polluted - even of failures. Reasoning: For automated tasks or people not familiar with Linux/my script, the disk should not be filled up with old garbage data. And for debugging, I usually add a '-d/--debug' option to have more verbose output and disable the cleanup on Ctrl+C (but still cleanup on normal exit).
But as I said, I don't believe there is the one true way. So except for pointing out that I had to ensure external cleanup in case the script was run by some auomated tasks in a permanent environment (read: native), I wouldn't seriously complain if I ever used one of your scripts :)
That's perfectly fine – even desirable – behaviour for a whole bunch of use cases. The thing is you can opt-in to that trivially with "trap EXIT INT TERM ABRT", whereas the reverse is harder and much less obvious, so it seems like a better design to me (although a "trap ALWAYS" shortcut would be even better so you don't need to list signals).
At this point it's difficult to change due to compatibility as people's bash scripts would break in subtle ways, but it's one of my many annoyances with bash (my view is that people really ought to ditch bash in favour of a better shell – zsh being the most obvious incremental improvement, though far from the only option – but this always proves to be a controversial opinion).
Did you mean "it's hard" instead of "it's not hard"?