Explanation for newbies:
-
Shell is the programming language that you use when you open a terminal on linux or mac os. Well, actually “shell” is a family of languages with many different implementations (bash, dash, ash, zsh, ksh, fish, …)
-
Writing programs in shell (called “shell scripts”) is a harrowing experience because the language is optimized for interactive use at a terminal, not writing extensive applications
-
The two lines in the meme change the shell’s behavior to be slightly less headache-inducing for the programmer:
set -euo pipefail
is the short form of the following three commands:set -e
: exit on the first command that fails, rather than plowing through ignoring all errorsset -u
: treat references to undefined variables as errorsset -o pipefail
: If a command piped into another command fails, treat that as an error
export LC_ALL=C
tells other programs to not do weird things depending on locale. For example, it forcesseq
to output numbers with a period as the decimal separator, even on systems where coma is the default decimal separator (russian, dutch, etc.).
-
The title text references “posix”, which is a document that standardizes, among other things, what features a shell must have. Posix does not require a shell to implement
pipefail
, so if you want your script to run on as many different platforms as possible, then you cannot use that feature.
That’s good, but if you like to name your arguments first before testing them, then it falls apart
#!/bin/bash set -euo pipefail myarg=$1 if [[ -z "${myarg}" ]] then echo "we need an argument!" >&2 exit 1 fi
This fails. The solution is to do
myarg=${1:-}
and then testEdit: Oh, I just saw you did that initialisation in the if statement. Take your trophy and leave.
Yeah, another way to do it is
#!/bin/bash set -euo pipefail if [[ $# -lt 1 ]] then echo "Usage: $0 argument1" >&2 exit 1 fi
i.e. just count arguments. Related,
fish
has kind of the orthogonal situation here, where you can name arguments in a better way, but there’s noset -u
in the end my conclusion is that argument handling in shells is generally bad. Add in historic workarounds like
if [ "x" = "x$1" ]
and it’s clear shells have always been Shortcut CitySide note: One point I have to award to Perl for using
eq/lt/gt/etc
for string comparisons and==/</>
for numeric comparisons. In shells it’s reversed for some reason? The absolute state of things when I can point to Perl as an example of something that did it betterPerl is the original GOAT! It took a look at shell, realised it could do (slightly) better, and forged its own hacky path!
I was about to say, half the things people write complex shell scripts for, I’ll just do in something like Perl, Ruby, Python, even node/TS, because they have actual type systems and readability. And library support. Always situation-dependent though.