Shell shock? No, ShellCheck! Find bugs in your scripts.

Updated: April 3, 2019

Writing good scripts is difficult. There's the obvious PEBKAC skill, of course, but also ancient magic and history, with legacy conventions going to Plan 9 and FLOW-MATIC, which most people don't really understand or care about when writing their software. Then, the lack of a Dostoevskian crime & punishment in software development also means codes can be lazy and write however they like.

A bunch of moons ago, I've come across a neat little program designed to make your shell script suck less. It's called ShellCheck, it's available as an online console, and you can also install it in pretty much any distro and then integrate in your workflows or whatnot. Intrigued, I went about a-explorin'.


Fire in the hole

I started with my own shell script - simWANsim, a program designed to simulate WAN network latency in a simple convenient way (no need for multiple interfaces, live media or such). This is a BASH script essentially, and I wanted to see how efficient and elegant it is. BTW, the script does not need to be executable to evaluate.

shellcheck "script name"

ShellCheck running

I was surprised by the amount of errors and warnings, but then, as I started reading, many of these were actually multiple instances of the same kind of bad coding practice, repeated several times through the script. Moreover, I realized that the errors made sense, they were written in a clear way, and it wasn't just random technobabble. Practical, useful suggestions - with examples - on how to fix your scripts.

One of the common errors was the use of backticks rather than $() notation. I also had several other lines in the same vein, the use of let expr, the lack of double quotation marks to prevent globbing and word splitting, and a few other minor issues ones like that.

In line 152:
EGREP=`which egrep`
^-----------^ SC2006: Use $(...) notation instead of legacy backticked `...`.
^---^ SC2230: which is non-standard. Use builtin 'command -v' instead.

Did you mean:
EGREP=$(which egrep)

In line 304:
let PRNT=$PRNT+1
^--------------^ SC2219: Instead of 'let expr', prefer (( expr )) .

I was impressed by the case study [sic]. Hi hi. I had used options that I haven't really handled, and I also didn't have a generic case for unspecified flags. Looks like a smart little suggestion. Most cunning.

In line 178:
case $flag in
^-- SC2213: getopts specified -a, but it's not handled by this 'case'.
^-- SC2213: getopts specified -s, but it's not handled by this 'case'.
^-- SC2220: Invalid flags are not handled. Add a *) case.

None of these are cardinal, but then why not. After all, if you can make your code as clean and elegant as possible, you eliminate the possibility for corner case errors and weird behavior. I don't like writing code, but if you are doing it, you might as well do it right.

I also tested a very generic script to see what happens when there are no errors. The command-line tool just exits, without any output. If you use the online tool, you will get a printed message that reads:

$ shellcheck myscript
No issues detected!

Finally, you can beautify your output, change output verbosity, format style and colors, force ShellCheck to work with a specific dialect of shell (including sh, bash, dash, and ksh), show wiki links, which can be useful for those looking for additional information and resources on their coding practices and errors, plus a few other options. All in all, it's simple, effective and elegant.


ShellCheck is a really cool utility. I don't normally care much for things of this kind, but I can appreciate beauty when there's some to be found. The tool itself has been written in Haskell, which puts us all in a completely different metaphysical plane, but we won't hold it against the author.

If you happen to use shell scripts in your environment, you might want to consider giving ShellCheck a go. I think you will be surprised, because there ought to be tons of tiny, legacy mistakes in your code, as people rarely go back and fix old things, and you end up with leftovers that no longer make sense or serve any purpose. In the age of unnecessary bloat, being frugal and elegant counts. This is a smart way to start your shell diet. And thus endeth another article.