Hacker News new | ask | show | jobs
by xyzzy_plugh 1863 days ago
> The rules are too tricky to remember even for shell experts -- there are persistent arguments on POSIX behavior that is over 20 years old, simply because it's so confusing.

I don't know, I find it easier to not use set -e. I find it significantly easier to just explicitly handle all my errors. Having my script exit at some arbitrary point is almost never desirable.

I find chaining && and || pretty intuitive.

  var=$(myfunc) &&
    echo OK ||
    {
      echo Not OK
      exit 1
    }
This is pretty contrived. I'd probably put the error handling in a function and then only handle the failure scenario:

  var=$(myfunc) || die 'Not OK'
  echo OK
I never run into problems, this always works as expected, I don't need any language or interpreter changes to fix it. Once you realize `if` is just syntactic sugar and [ is just `test` then the world gets pretty simple.
1 comments

The rules without -e are definitely less hairy than the rules with -e.

Are you regularly writing shell scripts that check all their errors? I'd be curious to take a look if any of them are public.

It's not impossible to do this -- git's shell scripts seem to do a decent job. However I think the vast majority of shell scripts don't check errors, so "set -e" is "closer to right", if not right. (And I claim it's nearly impossible to be "right" with state of the art with -e -- fixes in the shell itself are needed.)

I'll also note that Alpine Linux's apk package manager switched to "set -e" a few years ago. They are shell experts and even they found it difficult to check all their errors without it. apk is more than 1000 lines of shell IIRC.

I'm not your parent comments OP, but I don't like to use -e for similar reasons, and I do have public bash scripts written with explicit error handling [1].

I've tried using -e on multiple occasions, but always had to disable it again because it lead to even worse classes of errors. It hurt me more than it helped, but I also consider my explicit error handling quite pedantic and probably not the norm.

I feel that instead of fixing the problem it just shifts it around, because an exit code != 0 does not generally indicate an error:

* `((i++))` must now be written as `((i++)) || true` or it will probably kill your script, and short hand conditions become foot-guns:

* Statements such as `[[ $i -gt 3 ]] && continue` must now be written in long form in their own ifs, or `|| true` must be appended.

* Want to save the return code? Guess you have to use `command && ret=$? || ret=$?` now.

* Subshells with errors may exit independently and won't notify you of the error at all, because ylur parent is still alive afterwards.

The list goes on and on. Lots of strange edge cases appear. I recommend reading http://mywiki.wooledge.org/BashFAQ/105 which highlights some of them.

In the end, set -e requires you to think just as much as not using it to not randomly crash your program. It just shifts the problem to other statements. I already learned to handle errors in normal bash, and the only thing set -e requires me to do is to change my error handling style in those cases, which to me generally seem more obscure.

If I still have to use set -e, I always use something like the following snippet, so that I at least get a message:

``` set -e function eerr() { echo "error: $0:$1: command failed but status was never checked!" }; trap 'eerr "$LINENO"' ERR``` ```

[1] https://github.com/oddlama/gentoo-install/blob/develop/scrip...

Yeah I'm not surprised by that and don't disagree with it: as mentioned I think neither situation is ideal!