Shellcheck is an invaluable tool for anyone who writes, well, shell scripts. The tool will point out common and less common errors, such as forgetting to quote a variable substitution, not putting that space before the closing ]]
, or not testing if a variable substitution used with rm -Rf
might be empty.
Update 2019-11-20: The shellcheck project now has pre-compiled binaries available and I have updated instructions here.
You can use the tool’s website to check your code, but it is unwieldy, not to mention you or your organization might have concerns uploading all your code to some website, useful as it may be. You can install a shellcheck
command line tool, but the instructions available for macOS will only work with Homebrew.
If you already have Homebrew installed, or don’t mind installing it and only need to install
shellcheck
on a single Mac, then you can usebrew install shellcheck
and skip ahead to the end, where I share how to use theshellcheck
binary with BBEdit.
Relevant for MacAdmins
Homebrew may be a fine tool for individual users, but it is near-impossible to centrally manage a deployment of brew
let alone a piece software installed with brew
.
My attempts to build the shellcheck
binary without homebrew lead to several dead-ends. Shellcheck is written in Haskell Cabal, which can be easily installed with… brew
. There is also an official ghcup
script, which is the ‘recommended way to install Haskell’, but this script fails on macOS because it requires a tool named xz
. This is a (de-)compression tool, which is part of xz-utils
, whose website does not explain how to install on macOS, but can be easily installed with… guess… brew
…
Even without brew
, you have to install a number of tools that you probably don’t want hanging around on your production machine. I am sure cabal
is a fine environment to build other tools as well, but I don’t need it on my production system.
I would recommend running these steps on a virtual machine. That will simplify ‘cleanup’ as well as the ‘start over’ process, should you need it.
How to build the shellcheck binary for macOS
Commands shown are correct at the time this article was written and may change in the future. Links to original sources are given, so you can check for changes.
Developer Tools
- install Xcode or command line developer tools (CLI dev tools have the advantage of not being >6GB in size)
$ xcode-select --install
XZ Utils
Note: the macOS Archive Utility can deal with .xz
archives just fine. There is really no need on macOS to have the xz-utils installed, but the GHC Cabal installer requires them.
- download the
xz-util
source code from their project page - extract the archive by double-clicking it
- open Terminal, cd to the extracted directory, configure and build
$ cd ~/Downloads/xz-5.2.4
$ ./configure
$ sudo make install
- check to see of
xz
was installed correctly
$ xz --version
xz (XZ Utils) 5.2.4
liblzma 5.2.4
Install Pandoc
We will require pandoc
to build the man page for shellcheck
.
- download the installer from the Pandoc project page
- install Pandoc
Haskell Cabal
- install Haskell Cabal using the official installation script
$ curl https://get-ghcup.haskell.org -sSf | sh
- make sure the cabal environment is setup
$ source "$HOME/.ghcup/env"
$ cabal update
Shellcheck
- download/clone the
shellcheck
repository
$ git clone "https://github.com/koalaman/shellcheck.git"
- build the
shellcheck
binary (this will take a while)
$ cd shellcheck
$ cabal install
- this will build and install the
shellcheck
binary into~/.cabal/bin
, you can test if this worked with
$ ~/.cabal/bin/shellcheck --version
ShellCheck - shell script analysis tool
version: 0.6.0
license: GNU General Public License, version 3
website: https://www.shellcheck.net
man page
- there is also a man page in the repo, written in markdown format. The ReadMe says you can convert it to
man
format withpandoc
:
$ pandoc -s -f markdown-smart -t man shellcheck.1.md -o shellcheck.1
Pkg it up
- create a
payload
directory for the binary and man file and move the files there:
$ mkdir -p payload/local/bin
$ cp ~/.cabal/bin/shellcheck payload/local/bin/
$ mkdir -p payload/share/man/man1
$ cp shellcheck.1 payload/share/man/man1/
- build the pkg installer from the payload with
pkgbuild
$ pkgbuild --root payload --install-location /usr --identifier com.scriptingosx.pkg.shellcheck --version 0.6.0 shellcheck-0.6.0.pkg
Automation!
Of course, you can do this once and then forget about until the next update of shellcheck
. While I wrote this post, I had to go through these steps more than once and got bored with it halfway through the second cycle. So, there is a script, which you can get at this Github repo.
Since this script will install xz-utils
, cabal
, and pandoc
, I do not recommend to run this on your work machine. I use it with clean virtual machine. I suggest this workflow:
- boot to clean vm
- snapshot the vm
- open Terminal
- install developer command line tools:
xcode-select --install
- clone the script:
git clone https://github.com/scriptingosx/BuildShellcheckPkg
- run the script:
cd BuildShellcheckPkg; ./buildShellCheckPkg.sh
- confirm the prompts (once the cabal installation starts for good, the prompts are over)
- wait…
- wait…
- start doing other work such as answering emails, MacAdmins Slack, Twitter,…
- much later, remember there was something important, go to the vm, copy the brand new
shellcheck
pkg to your work machine - revert the vm to snapshot
- buy ‘Packaging for Apple Administrators’ to show your gratitude and learn how to wield
pkgbuild
yourself
Using shellcheck
Using the shellcheck
command line tool is very straightforward. Just pass one (or more) shell script files as arguments. There are some flags and options that you can read about in the --help
option or the man page.
$ shellcheck serial.sh
In serial.sh line 11:
serial_number=$(serial) # stores output of function serial in variable
^-----------^ SC2034: serial_number appears unused. Verify use (or export if used externally).
For more information:
https://www.shellcheck.net/wiki/SC2034 -- serial_number appears unused. Ver...
Use shellcheck with BBEdit
My favored text editor – BBEdit – has a tool that will display the output of tools like shellcheck. This allows you to click on an error or warning and see and edit the code right there in a BBEdit window.
To get this, pipe the output of shellcheck
into bbresults
:
$ shellcheck -f gcc serial.sh | bbresults
I have created a function in my .bash_profile
and .zshrc
, so I don’t have to remember the details:
function bbshellcheck {
shellcheck -f gcc "$@" | bbresults
}
If you do not know what the .bash_profile
or functions
are, then you can read about them here:
- About bash_profile and bashrc on macOS
- Configuring bash with aliases and functions
- Moving to zsh, part 2: Configuration Files – Scripting OS X
- Moving to zsh, part 4: Aliases and Functions
Note: you cannot use shellcheck
to check zsh
scripts. As of now it only works for sh
or bash
scripts. You can tell shellcheck
to ignore the #!/bin/zsh
shebang and interpret the script as using bash
syntax, which should work in most cases, but will not always have good results.
$ shellcheck -s bash script.zsh
Thanks for the article. As an admin supporting enterprise deployments, it’s incredibly frustrating having reading documentation which suggests the only method of installation is to leverage off brew…
I’ve taised a number of issues against Microsoft Azure CLI and others which have followed down this path.
FYI:
See our blog post for other options on integrating code analysis with BBEdit include shellshock, Pylint & Flake8
https://apple.lib.utah.edu/bbedit-code-analysis-integration/