simontatham,
@simontatham@hachyderm.io avatar

In bash, writing ${var?} instead of just ${var} or $var means if var isn't defined then bash will throw an error and not execute your command, instead of expanding it to "" and carrying on.

mv file1 file2 $subdir # oops, I overwrote file2
mv file1 file2 ${subdir?} # error message instead of disaster

My favourite use of this is for example commands in documentation, with placeholders for the user to fill in. Then it's OK if a user accidentally copy-pastes it without filling them in!

lanodan,
@lanodan@queer.hacktivis.me avatar

@simontatham That's part of POSIX btw.
And ${parameter:?} allows to also throw an error when it's null rather than only unset, plus ${parameter:?word} would throw word to standard error, which can allow for better errors.

(posix draft note, in the special case of ${@?} and ${*?} it's undefined behavior)

oldherl,
@oldherl@comfy.social avatar

@simontatham This semantic of ? is the opposite of it in many other modern languages, though.

simontatham,
@simontatham@hachyderm.io avatar

@oldherl well, the last thing anyone would accuse bash of (or any other POSIX-derived shell) is being modern!

But bash's use of ? here doesn't seem 180° away from the Rust ? operator, say. Both mean "if there's an error, propagate it to some far-away caller and do not continue running the code that would otherwise follow this statement". Every detail of the error representation is different, but the effect on control flow is identical.

aburka,
@aburka@hachyderm.io avatar

@simontatham this gets real confusing at $dayjob because in our custom YAML extensions (don't ask) the syntax ${var?} means to substitute var, unless it's undefined in which case leave it out. We do have syntax that does the same as this bash feature, but it's ${var!} instead

Rob_Russell,
@Rob_Russell@mastodon.cloud avatar

@simontatham I sometimes use set -e at the top of a script but it does so many unexpected things.

This tip is a more practical option in a lot of cases, thanks!

muvlon,
@muvlon@hachyderm.io avatar

@Rob_Russell @simontatham set -e is errexit, which is also nice but something else. To have ${var} error on undefined, you need set -u.

I reflexively start all of my scripts with ol' reliable set -euo pipefail.

simontatham,
@simontatham@hachyderm.io avatar

@muvlon @Rob_Russell thank you, I hadn't been aware of 'set -u' to make this behaviour the default!

(@hendric, I think that's what you were just asking for!)

nogweii,
@nogweii@nogweii.net avatar

@simontatham @muvlon @Rob_Russell @hendric if y'all didn't know, set -o pipefail is also very handy - it means that earlier command's exit codes won't be overridden by later commands that have been piped. That is $? is non-zero if any command in the pipeline is.

So fail | grep blah still results in $? being 1 (or whatever else)

muvlon,
@muvlon@hachyderm.io avatar

@nogweii @simontatham @Rob_Russell @hendric Yep! There are some pitfalls though, which is why I sometimes do opt out of pipefail.

Example: if foo | grep -q "bar"; then ... is something you might like to use. The -q makes grep quiet, i.e. it won't print matches. However! It will also make grep exit (successfully) on the first match. That by itself is fine, but it also closes grep's stdin, so if foo checks for errors, it might fail now. And with pipefail, your if is now never taken!

simontatham,
@simontatham@hachyderm.io avatar

@muvlon @nogweii @Rob_Russell @hendric yes, that is awkward. You'd almost like 'died of SIGPIPE' to be an exception, not counting as failure for pipefail purposes. Because it doesn't reflect badly on the pipe writer – it only means the reader lost interest, and it's up to the reader whether that was a bad thing.

(Similarly, why does Python default to printing a huge stack-trace on SIGPIPE, bah)

But one problem: SIGPIPE not on stdout might need to be an exception to the exception.

nogweii,
@nogweii@nogweii.net avatar

@simontatham @muvlon @Rob_Russell @hendric The combination of the three are so handy that I have an editor snippet called "strict" that I use in scripts to add set -euo pipefail. Makes bash a lot more sane!

jomo,
@jomo@mstdn.io avatar

@muvlon @Rob_Russell @simontatham this is a very good example of why I always use the more verbose option names. They are much harder to confuse:

set -o errexit
set -o nounset
set -o pipefail

Slightly related: I've seen a post recently where someone suggested to always use the full-length command options when using examples. That way you don't have to guess or look up the meaning, or use them without knowing what it does.

hendric,
@hendric@astronomy.city avatar

@simontatham I'm just a moron, but why would anyone want the default to be this vs the opposite?? "If you don't recognize this, STOP" seems way more sensible.

simontatham,
@simontatham@hachyderm.io avatar

@hendric don't ask me! That decision was made literally before I was born.

  • All
  • Subscribed
  • Moderated
  • Favorites
  • random
  • GTA5RPClips
  • DreamBathrooms
  • thenastyranch
  • magazineikmin
  • tacticalgear
  • cubers
  • Youngstown
  • mdbf
  • slotface
  • rosin
  • osvaldo12
  • ngwrru68w68
  • kavyap
  • InstantRegret
  • JUstTest
  • everett
  • Durango
  • cisconetworking
  • khanakhh
  • ethstaker
  • tester
  • anitta
  • Leos
  • normalnudes
  • modclub
  • megavids
  • provamag3
  • lostlight
  • All magazines