this post was submitted on 15 Jan 2025
568 points (98.5% liked)
linuxmemes
21813 readers
1172 users here now
Hint: :q!
Sister communities:
Community rules (click to expand)
1. Follow the site-wide rules
- Instance-wide TOS: https://legal.lemmy.world/tos/
- Lemmy code of conduct: https://join-lemmy.org/docs/code_of_conduct.html
2. Be civil
- Understand the difference between a joke and an insult.
- Do not harrass or attack members of the community for any reason.
- Leave remarks of "peasantry" to the PCMR community. If you dislike an OS/service/application, attack the thing you dislike, not the individuals who use it. Some people may not have a choice.
- Bigotry will not be tolerated.
- These rules are somewhat loosened when the subject is a public figure. Still, do not attack their person or incite harrassment.
3. Post Linux-related content
- Including Unix and BSD.
- Non-Linux content is acceptable as long as it makes a reference to Linux. For example, the poorly made mockery of
sudo
in Windows. - No porn. Even if you watch it on a Linux machine.
4. No recent reposts
- Everybody uses Arch btw, can't quit Vim, <loves/tolerates/hates> systemd, and wants to interject for a moment. You can stop now.
Please report posts and comments that break these rules!
Important: never execute code or follow advice that you don't understand or can't verify, especially here. The word of the day is credibility. This is a meme community -- even the most helpful comments might just be shitposts that can damage your system. Be aware, be smart, don't fork-bomb your computer.
founded 2 years ago
MODERATORS
you are viewing a single comment's thread
view the rest of the comments
view the rest of the comments
set -euo pipefail
is, in my opinion, an antipattern. This page does a really good job of explaining why. pipefail is occasionally useful, but should be toggled on and off as needed, not left on. IMO, people should just write shell the way they write go, handling every command that could fail individually. it's easy if you write adie
function like this:It only takes a little bit of extra effort to handle the errors individually, and you get much more reliable shell scripts. To replace -u, just use shellcheck with your editor when writing scripts. I'd also highly recommend https://mywiki.wooledge.org/ as a resource for all things POSIX shell or Bash.
After tens of thousands of bash lines written, I have to disagree. The article seems to argue against use of -e due to unpredictable behavior; while that might be true, I've found having it in my scripts is more helpful than not.
Bash is clunky. -euo pipefail is not a silver bullet but it does improve the reliability of most scripts. Expecting the writer to check the result of each command is both unrealistic and creates a lot of noise.
When using this error handling pattern, most lines aren't even for handling them, they're just there to bubble it up to the caller. That is a distraction when reading a piece of code, and a nuisense when writing it.
For the few times that I actually want to handle the error (not just pass it up), I'll do the "or" check. But if the script should just fail, -e will do just fine.
This is why I made the reference to Go. I honestly hate Go, I think exceptions are great and very ergonomic and I wish that language had not become so popular. However, a whole shitload of people apparently disagree, hence the popularity of Go and the acceptance of its (imo) terrible error handling. If developers don't have a problem with it in Go, I don't see why they'd have a problem with it in Bash. The error handling is identical to what I posted and the syntax is shockingly similar. You must unpack the return of a func in Go if you're going to assign, but you're totally free to just assign an err to
_
in Go and be on your way, just like you can ignore errors in Bash. The objectively correct way to write Go is to handle everyerr
that gets returned to you, either by doing something, or passing it up the stack (and possibly wrapping it). It's a bunch of bubbling up. My scripts end up being that way too. It's messy, but I've found it to be an incredibly reliable strategy. Plus, it's really easy for me to grep for a log message and get the exact line where I encountered an issue.This is all just my opinion. I think this is one of those things where the best option is to just agree to disagree. I will admit that it irritates me to see blanket statements saying "your script is bad if you don't set -euo pipefail", but I'd be totally fine if more people made a measured recommendation like you did. I likely will never use set -e, but if it gets the bills paid for people then that's fine. I just think people need to be warned of the footguns.
EDIT: my autocorrect really wanted to fuck up this comment for some reason. Apologies if I have a dumb number of typos.
I've been meaning to learn how to avoid using pipefail, thanks for the info!
Putting
or die “blah blah”
after every line in your script seems much less elegant than op’s solutionThe issue with
set -e
is that it's hideously broken and inconsistent. Let me copy the examples from the wiki I linked.Or, "so you think set -e is OK, huh?"
Exercise 1: why doesn't this example print anything?
Exercise 2: why does this one sometimes appear to work? In which versions of bash does it work, and in which versions does it fail?
Exercise 3: why aren't these two scripts identical?
Exercise 4: why aren't these two scripts identical?
Exercise 5: under what conditions will this fail?
And now, back to your regularly scheduled comment reply.
set -e
would absolutely be more elegant if it worked in a way that was easy to understand. I would be shouting its praises from my rooftop if it could make Bash into less of a pile of flaming plop. Unfortunately ,set -e
is, by necessity, a labyrinthian mess of fucked up hacks.Let me leave you with a allegory about
set -e
copied directly from that same wiki page. It's too long for me to post it in this comment, so I'll respond to myself.Woah, that
((i++))
triggered a memory I forgot about. I spent hours trying to figure out what fucked up my$?
one day.When I finally figured it out: "You've got to be kidding me."
When i fixed with
((++i))
: "SERIOUSLY! WTAF Bash!"From https://mywiki.wooledge.org/BashFAQ/105
This is great and thanks for taking the time to enlighten us 😄
No worries! Bash was my first language, and I still unaccountably love it after 15 years. I hate it and say mean things about it, but I'm usually pleased when I get to write some serious Bash.
Exercise 6:
That one was fun to learn.
Even with all the jank and unreliability, I think
set -e
does still have some value as a last resort for preventing unfortunate accidents. As long as you don't use it for implicit control flow, it usually (exercise 6 notwithstanding) does what it needs to do and fails early when some command unexpectedly returns an error.I personally don't believe there's a case for it in the scripts I write, but I've spent years building the
|| die
habit to the point where I don't even think about it as I'm writing. I'll probably edit my post to be a little less absolute, now that I'm awake and have some caffeine in me.One other benefit I forgot to mention to explicit error handling is that you get to actually log a useful error message. Being able to
rg 'failed to scrozzle foo.* because service y was not available'
and immediately find the exact line in the script that failed is so nice. It's not quite a stack trace with line numbers, but it's much nicer than what you have with bash by default or with set -e.Yup, and
set -e
can be used as a try/catch in a pinch (but your way is cleaner)I was tempted for years to use it as an occasional try/catch, but learning Go made me realize that exceptions are amazing and I miss them, but that it is possible (but occasionally hideously tedious) to write software without them. Like, I feel like anyone who has written Go competently (i.e. they handle every returned
err
on an individual or aggregated basis) should be able to write relatively error-handled shell. There are still the billion other footguns built directly into bash that will destroy hopes and dreams, but handling errors isn't too bad if you just have a littledie
function and the determination to use it.That's well put. I might put that at the start of all of my future comments about
bash
in the future.Yep. Bash was my first programming language so I have absolutely stepped on every single one of those goddamn pedblasters. I love it, but I also hate it, and I am still drawn to using it.