Debugging and ShellCheck

Bash · Advanced · 10 min

Shell bugs are often silent; tracing and static analysis find them in minutes.

Bash has built-in tools for seeing what a script really does:

  • bash -n script.sh parses the script without running anything: a quick syntax check.
  • bash -x script.sh, or set -x inside the script, prints every command after expansion, prefixed with +. Turn it off again with set +x to trace just one section.
  • Customise the prefix with PS4: PS4='+ ${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]:-main}: ' adds file, line and function to each traced line. Use single quotes so it expands at trace time.
  • trap '...' ERR can report the failing command ($BASH_COMMAND) and line ($LINENO).
  • set -o functrace and set -o errtrace make DEBUG and ERR traps apply inside functions.

ShellCheck is a static analyser that knows hundreds of shell pitfalls: unquoted variables (SC2086), for f in $(ls), useless cat, cd without error handling, unreachable code, variables used but never assigned, and bashisms in #!/bin/sh scripts. Every warning has an ID with a wiki page explaining it. Run it in your editor and in CI; disable a specific check on one line with a # shellcheck disable=SC2086 comment when you are sure.

For harder problems: print values to stderr with declare -p var, and reproduce the issue in a small test script before touching the real one.

Example

bash -n deploy.sh              # syntax check only, runs nothing
bash -x deploy.sh arg1         # trace every command
# inside a script:
PS4='+ ${BASH_SOURCE}:${LINENO}: '
set -x
total=$(( 2 + 3 ))
# + deploy.sh:6: total=5
set +x
trap 'echo "error at line $LINENO: $BASH_COMMAND" >&2' ERR
declare -p total >&2           # declare -- total="5"
shellcheck deploy.sh
# In deploy.sh line 3:
# rm -rf $dir/*
#        ^--^ SC2086 (info): Double quote to prevent globbing and word splitting.

Remember

  • bash -n checks syntax, set -x traces execution
  • A PS4 with ${LINENO} makes traces readable
  • Run ShellCheck on every script, in the editor and in CI

Watch out for

  • Leaving set -x on in a script that handles secrets: they are printed in the trace.

Check yourself

  1. What does `bash -n script.sh` do?
  2. Why should PS4 be set with single quotes?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.gnu.org/software/bash/manual/bash.html#The-Set-Builtin

Builds on

Unlocks

Nothing builds on this yet.