Tools I Love: Shellcheck

Posted on May 13, 2021

There are so many tools that I love! I feel I should give them a little shout-out once in a while. And there is one which I discovered just recently which has challenged some preconceptions I had as well as being really useful. It’s Shellcheck.

Shellcheck is a shell script analyzer. As far as I know, it supports both POSIX shell and bash and is able to identify errors, give you a way better error message than any of our beloved shells, and even suggests style improvements which are, in all cases I’ve encountered, very, very recommendable.

Nowadays I use it locally,1 but you can use it from their website as well. How do you use it? Super simple! Let’s say you write this piece of horrible POSIX sh:

#!/bin/sh

# This is HORRIBLE code... DON'T DO THIS KIND OF STUFF EVER EVER EVER!!!1 This
# is just for educational purposes!

files=$(ls -1 | grep '.txt')

IFS=$'\n'
for iter in $files; do
	cp "$iter" "$iter.copy"
	[ -z $? ] && echo -n 'Some error happened'
done

If we assume this script to be called the-horror, which is the only fitting name it should have, you just call Shellcheck like this and voilà:

$ shellcheck the-horror

In the-horror line 6:
files=$(ls -1 | grep '.txt')
        ^-- SC2010: Don't use ls | grep. Use a glob or a for loop with a condition to allow non-alphanumeric filenames.


In the-horror line 8:
IFS=$'\n'
    ^---^ SC3003: In POSIX sh, $'..' is undefined.


In the-horror line 11:
	[ -z $? ] && echo -n 'Some error happened'
                          ^-- SC3037: In POSIX sh, echo flags are undefined.

For more information:
  https://www.shellcheck.net/wiki/SC2010 -- Don't use ls | grep. Use a glob o...
  https://www.shellcheck.net/wiki/SC3003 -- In POSIX sh, $'..' is undefined.
  https://www.shellcheck.net/wiki/SC3037 -- In POSIX sh, echo flags are undef...

Pretty nice, isn’t it? Especially for someone like me who has learned shell scripting by need when something required that as a tool… Because, yeah, there are very good guides and tutorials out there, and there are the sacred POSIX specs out there as well, but a tool like this is great to make your code be more reliable. It doesn’t replace reading lots of other people’s code to get the gist of a language, platform, and culture… but it definitely helps.

As I told before, I use it locally. I think I should some time explain how I install things on my computer,2 but this one was the type of software I commonly install from the Arch Linux repositories. I did start using it on their hosted instance, but as soon as I found myself using it regularly… I now prefer to have it on my system, God forbid I need it while being offline for some reason.3

Now to the preconceptions part. To install Shellcheck you need to pull dozens of dependencies because it’s written in Haskell; you may check out the output of pactree shellcheck here if you want to see it for yourself. I know people who dismiss this tool precisely because of this fact. I myself don’t like pulling lots of dependencies for a seemingly “simple” tool like this one, right? “There must be something more lightweight, isn’t there? Something in C? Something that doesn’t seem to install all of Haskell?”

I love minimalist software. I find it more manageable. But it is so easy to fall into the trap of minimalist for the sake of minimalism. Some tasks need a complex infrastructure. OK, maybe someone knows of or even writes a tool that is able to do the same (or more) Shellcheck does and is written in C, but I’m not aware of it. I’d totally switch to that if it existed!4 Parsing and analyzing languages (in general) is hard and I totally see the benefits of using a very high-level language to do that. I haven’t studied the code (I don’t know any Haskell beyond the very basics) and my parser code is usually very basic… but there must be some reason why Haskell was chosen. Maybe it’s just that we still need to figure out other ways to do this?

And you know what? It gets the job done fantastically. My POSIX shell scripts are portable to a large scale thanks to Shellcheck! I mean, who cares how many packages it pulls in as dependencies if it helps me write code as I wanted it to be? I could make exactly the same point about LaTeX… Yeah, troff is way more minimal, but it’s unable to do half the things I need to in the way I need/want them to be. The same goes even for GCC or web browsers… Look, minimalism is an awesome ideal, but we’re living in the real world, hun. Let’s concentrate in writing new tools that improve the general landscape, instead of rejecting things only because they don’t fit into our preconceptions, shall we?

Kudos to the Shellcheck dev team with all my love! You guys are writing a very nice and useful tool! So there goes my shout-out for the project and I truly hope my readers check it out… especially if you’re learning shell scripting.

I think I’ll be writing more on the tools I love as frequently as I can. Let’s spread some nice positivity… Excited to show all of you ome glimpses of the tech I use!


  1. More on this later! ↩︎

  2. I keep foreshadowing future posts in almost all posts on this blog! ↩︎

  3. It happens. In fact, I think there’s a lot to learn from people who deliberately go living 100% offline like the guys from Hundred Rabbits… I won’t ever become that radical (I guess?), but I do believe an offline-first philosophy prevents lots of potential issues you only become aware of when… well… you don’t get a reliable connection… ↩︎

  4. devscripts’s checkbashisms is way more limited and is meant for a different use-case, actually. ↩︎