6 ms·
ShellCheck your scripts!
by whateveracct 3y ago
ShellCheck your scripts!
- mr_toad 3y agoOr use set -u to fail early. Or use [ -n ${FOO-} ] which will replace the unset variable with an empty string.
- yjftsjthsd-h 3y agoPreferably you'd use set -u to avoid certain problems, and also keep using shellcheck for all the other things it can catch.
- LegibleCrimson 3y agoThat bottom one will also fail. The empty string is not treated as a shell word. You need double quotes.
- kazinator 3y agoThat 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.
- js2 3y agoThey 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=""
- kazinator 3y agoThat colon makes no difference if the replacement is blank.
- js2 3y agoHoly 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/V3_chap02.html#tag_18_06_02 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V...
- kazinator 3y agoSo ${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.
- ninkendo 3y ago> 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.)
- neuromanser 3y ago: ${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))
- ninkendo 3y ago> 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.
- neuromanser 3y ago> 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).
- 3y ago
- Xiol32 3y agoset -euo pipefail Effectively strict mode for shell scripts.
- sweeter 3y ago"set -x" is a life saver for debugging. Also "set -euo pipefail" so a script just exits on errors or unexpected behavior. If done well you can really reign in squirrely behavior. Bash has some odd behaviors and footguns but it can also be surprisingly reliable and versatile. Ive caught some seriously messed up stuff that I couldn't figure out otherwise, using set -x. Also shellcheck will forcefully hammer good practice into your head and catch a ton of hangups that are hard to know before making the mistakes. also setting backup variables is a good idea like: pictures="${pics_dir:-$HOME/Pictures}"