Automation projects
Test and review the script
Run syntax checks, ShellCheck, failure cases, clean-environment tests, and a documented cleanup path.
10 minute lesson
A script is a program. It needs tests for inputs, failures, side effects, and the environment it assumes. Most shell scripts get none of that: they run once on the author’s machine on a good day, then get trusted for years. This review pass closes the course projects.
Run static checks
bash -n script.sh
shellcheck script.sh
env -i PATH=/usr/bin:/bin bash script.sh
bash -n parses the script without running it — a pure syntax check that catches an unclosed if before anything executes.
ShellCheck is the linter for shell. It knows every classic from this course: unquoted expansions, read without -r, parsing ls. Each finding has a code you can look up:
shellcheck backup.sh
# In backup.sh line 12:
# tar -czf $archive -C $source_directory .
# ^------^ SC2086: Double quote to prevent globbing and word splitting.
The third command is the environment test. env -i starts from an empty environment and hands the script only a minimal PATH. A script that works in your terminal but depends on your aliases, your PATH additions, or a variable you exported months ago fails here — exactly the way it will fail under cron at 03:00.
Exercise real failures
Static checks can’t see behavior. Add a test directory with disposable fixtures and run the script against trouble: missing commands, interrupted work (Ctrl-C mid-run), weird filenames like 'has space.txt' and -dash.txt, and repeated execution — a second run must not corrupt what the first produced.
For each case, check the three things every caller sees: exit status, standard error, and side effects on disk. A failure that exits zero is a bug. So is a success that leaves temporary files behind — the cleanup path deserves a test of its own.
Warnings are a conversation
Static analysis is guidance, not proof. Sometimes ShellCheck flags something you did on purpose, like an intentional word split. Understand a warning before suppressing it, and document deliberate exceptions:
# shellcheck disable=SC2086 # $TAR_FLAGS is intentionally split into words
tar $TAR_FLAGS -czf "$archive" .
A disabled check with a comment is a recorded decision. A disabled check without one is a future bug report with your name on it.
Lesson completed