Bash Scripts Need Love Too

Cole Brumley
Senior Software Engineer

Code. Code never changes…

If you’re going to automate your infrastructure, chances are you’re going to have shell scripts involved. Scripts are the glue that holds so many of our systems together, yet we frequently don’t treat them as the first class code citizens they are. Bash is especially prone to stylistic and maintenance issues because its syntax is so loose. Tabs or spaces? Yes. How about three ways to define a function? Sure, why not?

OMG, why are you echoing that to a pipe? Just use <<<

This is why we can’t have nice things. With this much freedom, and the fact that 1337 bash skillz are a universally respected sign of techno-legitimacy, the sysadmin one-upsmanship is a foregone conclusion.

One of my favorite features of Go is the syntactically-mandated formatting. Your code just straight up won’t compile if you don’t follow the language’s style guide. It was designed from the ground up to be simple and easy to learn, and one of the most brilliant ways the devs ensured this was to guarantee that every go file you open will follow the same format.

I can’t tell you how many times I’ve opened someone else’s bash scripts and felt like this (I’ve spent plenty of time on the other end as well):

XKCD always applies

Let me be clear: I didn’t feel this way because the scripts were bad or wrong (most of the time). Half of them were too slick for my few remaining brain cells to comprehend, it’s the other half that looked like a house built by a child with a hatchet and a picture of a house. You could happily go your entire career without ever needing to know that bash can natively tell you the extension of a file with ${FILENAME##*.}, and that’s okay, I care much more about what you get done then the nitty gritty of how you got there.

You’re probably not going to be the only one working with your scripts, so we really should have some form of guard rails to keep the cart on. A major tenet of devops and site reliability engineering is treating your infrastructure code just like production code. Unfortunately shell scripts frequently get the short end of the stick, either living on their target box and being directly updated there, or just being checked into SCM and ignored at build time. Doing it right® means there should be:

  1. Automated builds
  2. Tests
  3. Code quality analysis
  4. Automated deployments

Half of this list is easy to implement, assuming you have your production code built and deployed in an automated fashion. Make sure all your scripts live in a SCM repo and follow the same build/deploy pipeline as your production code, and numbers 1 and 4 are in the bag.

Turns out that number 3 isn’t too bad either. Bash is well covered with Shellcheck, which checks for tons of potential script issues. It’s a typo life saver, and the well-organized documentation is helpful for learning how not to write shell scripts. I do occasionally practice what I preach, by the way.

Testing is something not usually associated with shell scripts, but is surprisingly well covered too. There are TAP-compliant frameworks and unit testing frameworks for bash. Some open source projects allegedly test their shell scripts, but I have yet to see any of these frameworks used in a for-profit shop. Maybe I’ve just been unlucky.

Writing supportable scripts is much easier when you have a defined style. You don’t even need to create your own! There are many open source style guides to choose from, but Google’s guide is always a solid bet if you have no idea where to start.

Informal polling in the office (okay, I asked Justin) revealed that we haven’t seen anyone applying these tools to shell scripts in the wild. Does your organization use Shellcheck and BATS religiously, or is scripting a free-for-all?


  • Michael Fritzius

    Completely agree. It’s not made easier by the fact that, a lot of shell scripts do low-level grungy stuff well, and then don’t get touched for months or possibly years.

    Great words, Cole. Style is important.

Comments are closed.