While sharing the solution to issues you encountered is great, sometimes tools are worth mentioning even if you did not build them or have issues with them. Most of the IT staff would not be where they are now without good tooling, this post is to add praise to one of those tools. Perhaps I will do this more often, but first lets discuss: Shellcheck.
Since a couple years I have incorporated Shellcheck in my daily bash shell script writing. It has greatly improved my scripts, made them more readable and the result is clean code without any nasty surprises. Shellcheck gives sane feedback to your scripts, provides best practices and reports syntax issues. The result is uniform and clean scripts that are readable. The best feature about Shellcheck is that if you made an error, it will point you to the SC code that can be looked up on the wiki of the shellcheck repo: https://github.com/koalaman/shellcheck
With shellcheck you can simply check your script, the output will be a return code based on the result of your script:
LT-rogier:test rogier$ shellcheck myscript.sh
LT-rogier:test rogier$ echo $?
0
Lets create a script with syntax issues, and see the result. This script sleeps for 5 seconds and after this it prints hi:
#!/bin/bash
SLEEPER=`sleep 5`
${SLEEPER}
echo hi
The script looks fine, it works and gives the result you want. There is however an issue with this script, this is the output when I used shellcheck:
LT-rogier:test rogier$ shellcheck ./myscript.sh
In ./myscript.sh line 3:
SLEEPER=`sleep 5`
^-------^ SC2006: Use $(...) notation instead of legacy backticked `...`.
Did you mean:
SLEEPER=$(sleep 5)
For more information:
https://www.shellcheck.net/wiki/SC2006 -- Use $(...) notation instead of le...
The result is easy feedback that gives actionable items that you can fix right away.
Shellcheck comes in many editors these days as an extension, for example this is a little bash script to install shellcheck in vscode:
install_ext_shellcheck() {
code --install-extension timonwong.shellcheck
}
main() {
install_ext_shellcheck
}
main
If you really like shellcheck, you can add a script to your repo to test your bash scripts in a pipeline. Example of a simple little script that I named test.sh
:
#!/bin/bash
set -e
set -o pipefail
ERRORS=()
# find all executables and run `shellcheck`
for f in $(find . -type f -not -iwholename '*.git*' | sort -u); do
if file "$f" | grep --quiet shell; then
{
shellcheck "$f" && echo "[OK]: successfull: $f"
} || {
# add to errors
ERRORS+=("$f")
}
fi
done
if [ ${#ERRORS[@]} -eq 0 ]; then
echo "No errors, YAY!"
else
echo "These files failed shellcheck: ${ERRORS[*]}"
exit 1
fi
Since shellcheck is such an important tool for me I have made a docker container that I use in my personal pipelines.
You can create a Makefile
to kick this off:
.PHONY: test shellcheck
# If session is non interactive we do not want to attach TTY
# When its interactive you need to be able to ^C
INTERACTIVE := $(shell [ -t 0 ] && echo 1 || echo 0)
ifeq ($(INTERACTIVE), 1)
DOCKER_FLAGS += -t
endif
test: shellcheck
shellcheck:
docker run --rm -i $(DOCKER_FLAGS) \
--name df-shellcheck \
-v $(CURDIR):/usr/src:ro \
--workdir /usr/src \
anldisr/shellcheck ./test.sh
You can then kick off the test with Make test
In Bitbucket you can set up a pipeline to kick it off, this is an example bitbucket pipeline yaml file:
options:
docker: true
pipelines:
default:
- step:
script:
- make test
And if you really really want to disable that warning for a syntax issue, it is also possible. You can disable the warning for the part of the script by adding in the line above:
# shellcheck disable=SC1234
The result is that your bash scripts all have the same uniform look, no syntax issues or surprises anymore. The tool is fun to use, informative and helps you improve your scripts.