Validating Syntax for Bash Scripts with ShellCheck

Luke Skywalker
4 min readFeb 27, 2022

--

Overview

ShellCheck is a GPLv3 tool that gives warnings and suggestions for bash/sh shell scripts:

ShellCheck

The goals of ShellCheck are

  • To point out and clarify typical beginner’s syntax issues that cause a shell to give cryptic error messages.
  • To point out and clarify typical intermediate level semantic problems that cause a shell to behave strangely and counter-intuitively.
  • To point out subtle caveats, corner cases and pitfalls that may cause an advanced user’s otherwise working script to fail under future circumstances.

From your terminal

Let us install and validate shellcheck (on macOS)

~  brew install shellcheck                                                                                                                                                             
==> Downloading https://ghcr.io/v2/homebrew/core/shellcheck/manifests/0.8.0
Already downloaded: /Users/macpro/Library/Caches/Homebrew/downloads/95affa345c01b7e2e46b5f9fa41e61267e61f01af1ba07385a9de41d1ec519b8--shellcheck-0.8.0.bottle_manifest.json
==> Downloading https://ghcr.io/v2/homebrew/core/shellcheck/blobs/sha256:cfd8c8e8d8927dfd4b83593f539690a6083b075b0a1ff8a66578e8bb810d3db9
Already downloaded: /Users/macpro/Library/Caches/Homebrew/downloads/64bf6d6e544255397ff1cd9bb6eba476c62ebfd7306ec2b0dd26d75319eb0f70--shellcheck--0.8.0.monterey.bottle.tar.gz
==> Pouring shellcheck--0.8.0.monterey.bottle.tar.gz
🍺 /usr/local/Cellar/shellcheck/0.8.0: 7 files, 9.7MB
==> Running `brew cleanup shellcheck`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
~  shellcheck
No files specified.
Usage: shellcheck [OPTIONS...] FILES...
-a --check-sourced Include warnings from sourced files
-C[WHEN] --color[=WHEN] Use color (auto, always, never)
-i CODE1,CODE2.. --include=CODE1,CODE2.. Consider only given types of warnings
-e CODE1,CODE2.. --exclude=CODE1,CODE2.. Exclude types of warnings
-f FORMAT --format=FORMAT Output format (checkstyle, diff, gcc, json, json1, quiet, tty)
--list-optional List checks disabled by default
--norc Don't look for .shellcheckrc files
-o check1,check2.. --enable=check1,check2.. List of optional checks to enable (or 'all')
-P SOURCEPATHS --source-path=SOURCEPATHS Specify path when looking for sourced files ("SCRIPTDIR" for script's dir)
-s SHELLNAME --shell=SHELLNAME Specify dialect (sh, bash, dash, ksh)
-S SEVERITY --severity=SEVERITY Minimum severity of errors to consider (error, warning, info, style)
-V --version Print version information
-W NUM --wiki-link-count=NUM The number of wiki links to show, when applicable
-x --external-sources Allow 'source' outside of FILES
--help Show this usage summary and exit

Run shellcheck yourscript in your terminal for instant output.

In your editor

Please refer to ShellCheck for compatible list of editors.

ShellCheck for Visual Studio Code

Integrates ShellCheck into VS Code, a linter for Shell scripts.

vscode-shellcheck (this “extension”), requires ShellCheck (the awesome static analysis tool for shell scripts) to work.

ShellCheck for VS Code

ShellCheck in Action

Create a simple bash script “shellcheck.sh” with below code:

#! /bin/bashecho -n “Enter a number: “
read -r NUM
if [[ $NUM -gt 10 ]]
then
echo “The variable is greater than 10.”
else
echo “The variable is equal or less than 10.”
fi

Now, let us validate our bash script

~/Documents/scripts/shellcheck  shellcheck shellcheck.sh                                                                                                                                   ~/Documents/scripts/shellcheck 

ShellCheck returns no syntax errors.

Now, let us remove then from if…then statement in our bash script. It should look like below:

#! /bin/bashecho -n “Enter a number: “
read -r NUM
if [[ $NUM -gt 10 ]]
echo “The variable is greater than 10.”
else
echo “The variable is equal or less than 10.”
fi

Validate the script now to see if shellcheck can identify the syntax error:

~/Documents/scripts/shellcheck  shellcheck shellcheck.sh                                                                                                                            In shellcheck.sh line 6:
if [[ $NUM -gt 10 ]]
^-- SC1049 (error): Did you forget the 'then' for this 'if'?
^-- SC1073 (error): Couldn't parse this if expression. Fix to allow more checks.
In shellcheck.sh line 8:
else
^-- SC1050 (error): Expected 'then'.
^-- SC1072 (error): Unexpected keyword/token. Fix any mentioned problems and try again.
For more information:
https://www.shellcheck.net/wiki/SC1049 -- Did you forget the 'then' for thi...
https://www.shellcheck.net/wiki/SC1050 -- Expected 'then'.
https://www.shellcheck.net/wiki/SC1072 -- Unexpected keyword/token. Fix any...

ShellCheck validates the script and clearly outputs that syntax errors.

Test Bash’s noexec mode to see if it can effectively catch syntax errors

First, let us add then back to the script and remove [[ from the script as shown below:

#! /bin/bashecho -n "Enter a number: "
read -r NUM
if $NUM -gt 10 ]]
then
echo "The variable is greater than 10."
else
echo "The variable is equal or less than 10."
fi

Now, let us see if noexec can catch the syntax error:

~/Documents/scripts/shellcheck  bash -n shellcheck.sh                                                                                                                                  ~/Documents/scripts/shellcheck 

noexec couldn’t catch the syntax error.

Now, let us validate the same script with Shellcheck:

~/Documents/scripts/shellcheck  shellcheck shellcheck.sh                                                                                                                                   In shellcheck.sh line 6:
if $NUM -gt 10 ]]
^-- SC2171 (warning): Found trailing ]] outside test. Add missing [[ or quote if intentional.
For more information:
https://www.shellcheck.net/wiki/SC2171 -- Found trailing ]] outside test. A...
~/Documents/scripts/shellcheck 

ShellCheck validated the bash script and clearly indicates that [[ are missing.

Conclusion

While ShellCheck is mostly intended for interactive use, it can easily be added to builds or test suites. It makes canonical use of exit codes, so you can just add a shellcheck command as part of the process. We have also seen ShellCheck can catch errors that are missed by noexec. Overall, nice little tool to validate your bash scripts.

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Luke Skywalker
Luke Skywalker

Written by Luke Skywalker

Protector of the Cloud. 404 bio not found

No responses yet

Write a response