Best Practices for Shell Scripts

The shell is an odd beast. Although it goes against every current trend in software engineering (strong typing, compile checks over runtime checks, ...), shell scripts are here to stay, and still constitute an important part of every developer's life.

The weird thing about shell scripts is that even strong advocates of good practices gladly forget all they know when it comes to shell scripting.

Versioning? Why bother, it's disposable code.

Code quality? That's just a shell script, it's garbage anyway.

Testing? Nah. There aren't any decent tools for that.

Wrong, wrong, and wrong. Shell scripts have value. Everything you do for real code should be done for non trivial shell scripts even for a one-time script. That includes versioning, code reviews, continuous integration, static code analysis, and testing.

Here is a summary of everything that can, and should be done when writing shell scripts.

Note: This article will use Bash as a reference shell. Most of the content can be transposed to other POSIX compliant shells.

Keep your scripts in version control

Keeping shell scripts under version control has multiple advantages:

Keeping shell scripts under version control has multiple advantages:

Please, from now on, version all your shell scripts before running them. Have someone reviewing your scripts in priority before executing them in production. It's not a waste of your coworkers' time, it's a time saver for the team.

Improve the quality of your scripts with ShellCheck

Although you can check the syntactic validity of your scripts with the command bash -n, much powerful tools exist.

ShellCheck is a static code analysis tool for shell scripts. It's really an awesome tool which will help you improve your skills as you use it. So do use it. You can install it globally on your machine, use it in your continuous integration, and it even [ There really are no downsides to using ShellCheck and it can save you from yourself.

If Steam had used ShellCheck in 2015, this line would never have made it to production:

rm -rf "$STEAMROOT/"*

This code violates the SC2115 rule from ShellCheck.

Use Bash unofficial strict mode

The unofficial strict mode comes from Aaron Maxwell's article "Use the Unofficial Bash Strict Mode (Unless You Looove Debugging)". He suggests to start every Bash script with the following lines:

set -euo pipefail