Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That is false. There is no difference between ${FOO} and ${FOO-}. Both disappear if unquoted, and FOO is unset or blank:

  $ printf "<%s>\n" alpha ${beta} omega
  <alpha>
  <omega>
  $ printf "<%s>\n" alpha ${beta-} omega
  <alpha>
  <omega>
The form ${var-} form is useful for safely evaluating a variable that might be unset, when "set -u" mode is in effect, and for whatever reason we cannot just fix the script so that the variable is set.


They meant "${FOO:-}" which should still be quoted.

The general form is "${FOO:-default}" where default can itself be another variable or whatever string you want.

I usually prefer to set default values at the top of a script though using this idiom:

   : "${FOO:=bar}"
And when creating a local variable I'll immediately set it to an empty string if there's a chance it won't be assigned later:

  local foo=""


That colon makes no difference if the replacement is blank.


Holy crap, 25 years of writing shell scripts and I just learned the difference:

With colon, tests variable for unset or empty. Without the colon tests only for unset. It's POSIX too:

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...


So ${foo-bar} will not expand to bar if foo exists, but is empty. The empty value will prevail. ${foo:-bar} will expand to bar.

If we have nothing in place of bar, they are effectively same.


> and for whatever reason we cannot just fix the script so that the variable is set

I use this pattern all the time for variables that should be overridable by whoever is calling the script, ie. `FORCE="${FORCE-no}"`, overridable with `FORCE=yes foo.sh`. I'm not sure of any other way to do this.

(Yes, using getopt or other option parsing is better, but for my own scripts, env vars are just such a simpler way to pass options, and after 20 years of using bash/unix/linux I still can't write a getopt stanza from memory.)


    : ${FORCE=no}
Also, it's not so difficult

    while getopts :hab:c o; do
      case $o in
      a) opt_a=x ;;
      b) opt_b="$OPTARG" ;;
      c) opt_c=x ;;
      h) usage 0 ;;
      ?) usage 1 $o "$OPTARG" ;;
      esac
    done
    shift $((OPTIND - 1))


> Also, it's not so difficult

Heh, was that an attempt at sarcasm? That's super difficult to do from memory, at least for me. Maybe I'm not as good at memorizing things as you are.


> Heh, was that an attempt at sarcasm?

There was definitely a wink component, but at the same time, I meant it.

Half the code is just case / esac syntax, which you can (i do) find plenty use for outside of getopts. getopts itself is… manageable. In the end, the code is such a strong pattern, it's basically a snippet. The lack of variation is what makes it kinda easy to remember. Or you could put it in your notes or a gist and copy/paste.

> That's super difficult to do from memory, at least for me. Maybe I'm not as good at memorizing things as you are.

Nah, my memory is shot. It's a matter of practice, and not being shy with man pages. Use it often enough, it's in memory; after a long hiatus, the details are a "/^\s*getopts \[" away (assuming your man pager is less).


I find it's much better to have a copy-pasted piece of code which turns all command line options into variables in a certain namespace (provided the variables are defined beforehand)

I.e. user runs:

  script --foo --bar=yes --no-xyzzy --uiuez"
the script then sets these existing variables:

  opt_foo=y
  opt_foo_given=y

  opt_bar=y
  opt_bar_given=y

  opt_xyzzy=
  opt_xyzzy_given=y
However, the variable opt_uiuez doesn't exist and so it bails:

  script: no such option: --uiuez
With such a piece of code, all you do is define the options you support via assignments like "opt_foo=". You can give them default values this way. Include that piece of boiler-plate code. Done.

To add a new option, just define the variable. Done.

Check its value wherever needed, and possibly the _given, if the code needs to know whether it's working with the default value, or an explicitly given value. That's it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: