Computing Foundations › Systems Foundations: Storage, Observability, and Tooling › Day 37
Hands-on lab — Day 37: Debuggers, Linters, and Formatters
- ← Back to the Day 37 lesson
- Open the hands-on files on GitHub — clone or download them from the public labs repository
- Local path in your clone:
labs/sections/computing-foundations/day-037-debuggers-linters-and-formatters/
Commands
Setup
cd labs/sections/computing-foundations/day-037-debuggers-linters-and-formatters Run
bash examples/quality_check.sh examples/samples/buggy.sh
bash starter/quality_check.sh examples/samples/buggy.sh Test
bash tests/run_tests.sh File tree
examples/quality_check.sh examples/samples/buggy.sh expected-output/FIELDS.md expected-output/quality-check-no-shellcheck.txt expected-output/tests.txt metadata.yml README.md requirements/README.md security.md starter/quality_check.sh starter/quality-worksheet.md tests/run_tests.sh troubleshooting.md
Lab README
Day 037 lab — Lint and Format a Script
Lesson
- Lesson title: Debuggers, Linters, and Formatters
- Day number: 37 of 365
- Lesson article: https://ai-roadmap-365.github.io/day-037-debuggers-linters-and-formatters
- Lab files: everything you need is in this directory — follow “How to run” below.
- Browse the course locally: from the repository root, this lab also appears in the course website at
/labs/day-037-debuggers-linters-and-formatterswhen the site is running.
Purpose
Day 37's lesson explains debuggers, linters, and formatters. This lab makes
two of them concrete on a real, deliberately flawed shell script: you run a
small quality pipeline — a syntax check (bash -n), a lint pass (ShellCheck,
if installed), and a formatting check (trailing whitespace and tabs) — and
learn to read each finding for what it is. It is a miniature of the automated
quality gate the Week 6 project builds.
Learning objectives
- Run
bash -nand explain what a syntax check does and does not prove. - Run a lint pass and name the real bugs a shell linter catches (unquoted
variables, unused variables, fragile
[ ]tests). - Run a formatting check and distinguish layout issues from correctness bugs.
- Experience graceful degradation: a tool that reports clearly when an optional dependency (ShellCheck) is absent instead of failing.
- Complete a working shell script by filling in four well-specified exercises.
Prerequisites
- The Day 37 lesson (read it first — it explains every tool this lab runs).
- Day 36 (a configured editor) and basic shell scripting from Week 2.
- A terminal: Terminal.app (macOS), any terminal (Linux), or WSL/Git Bash (Windows).
Supported operating systems
- macOS — fully supported (tested on macOS, Apple Silicon).
- Linux — fully supported (any distribution with
bash,grep,sed). - Windows — run the scripts unmodified inside WSL or Git Bash.
Hardware requirements
Any computer made in roughly the last 15 years. The lab only reads and analyzes small text files; it needs no minimum RAM, disk, or GPU.
Required software
bash(3.2 or newer — preinstalled on macOS and Linux).- Standard utilities:
grep,sed,printf,mktemp— all preinstalled. - Optional: ShellCheck (free) enables the lint step; the lab works without it.
Free and open-source options
Everything here is free and open source. bash and every utility ship with
your OS, and ShellCheck — the one optional extra — is free and open source
(see requirements/README.md). No account, API key, or purchase is needed.
Installation
None required. Copy this directory (or clone the repository) and change into it:
cd labs/sections/computing-foundations/day-037-debuggers-linters-and-formatters
To enable the lint step, optionally install ShellCheck (free):
brew install shellcheck (macOS) or sudo apt install shellcheck (Debian/Ubuntu).
File structure
day-037-debuggers-linters-and-formatters/
├── README.md ← you are here
├── metadata.yml ← machine-readable lab metadata
├── starter/
│ ├── quality_check.sh ← YOUR working file (4 exercises)
│ └── quality-worksheet.md ← worksheet for the practice assignment
├── examples/
│ ├── quality_check.sh ← completed reference quality gate
│ └── samples/
│ └── buggy.sh ← deliberately flawed sample to analyze
├── tests/
│ └── run_tests.sh ← automated checks
├── expected-output/
│ ├── quality-check-no-shellcheck.txt ← real captured run (no shellcheck)
│ ├── tests.txt ← real captured test run
│ └── FIELDS.md ← what to look for; platform notes
├── requirements/
│ └── README.md ← dependency + optional ShellCheck install
├── troubleshooting.md
└── security.md
How to run
From this directory:
## 1. Look at the flawed sample and confirm the shell can parse it
cat examples/samples/buggy.sh
bash -n examples/samples/buggy.sh # no output = valid syntax
## 2. Run the full quality check (syntax + lint + formatting)
bash examples/quality_check.sh examples/samples/buggy.sh
## 3. Your task: complete the four exercises in the starter, then run it
bash starter/quality_check.sh examples/samples/buggy.sh
## 4. Check your work
bash tests/run_tests.sh
What the commands do
bash -n examples/samples/buggy.sh— the shell's built-in syntax check: parses the script without running it; prints nothing and exits 0 when valid.bash examples/quality_check.sh <file>— runs three checks and prints a report: (1)bash -nsyntax, (2) ShellCheck if installed — otherwise a clear SKIP describing what it would catch, (3) agrep-based formatting check for trailing whitespace and tab indentation. It always exits 0.bash starter/quality_check.sh <file>— the same skeleton with four checks left as numbered exercises; each comment names the exact command to add.bash tests/run_tests.sh— verifiesbash -nflags a broken variant, the formatting check flags trailing whitespace and tabs, the quality check exits 0, and the lint step skips gracefully (or runs) depending on ShellCheck.
Expected output
See expected-output/quality-check-no-shellcheck.txt
— a real captured run on a machine without ShellCheck:
=== Quality check: examples/samples/buggy.sh ===
[1/3] Syntax check (bash -n)...
ok: script is syntactically valid.
[2/3] Lint check (shellcheck)...
SKIP: shellcheck is not installed on this machine.
Install it (free) to catch bugs like:
- SC2086: unquoted $variable may word-split or glob
- SC2034: variable appears unused
- using [ ] where [[ ]] is safer
See requirements/README.md for install instructions.
[3/3] Formatting check (trailing whitespace / tabs)...
FAIL: found 1 line(s) with trailing whitespace.
13:echo "Hi, $name"
FAIL: found 1 line(s) containing tab indentation.
14: echo "all done"
Summary: syntax OK; lint skipped (shellcheck absent); formatting issues found.
With ShellCheck installed, step [2/3] shows its real findings instead of the
SKIP block. See expected-output/FIELDS.md for
platform notes.
Validation steps
- Run
bash examples/quality_check.sh examples/samples/buggy.sh— it must print all three sections and exit 0. - Confirm the formatting section reports the trailing-whitespace line (13) and the tab line (14).
- Complete the four exercises in
starter/quality_check.shand run it; its formatting section should now match the reference. - Fill in
starter/quality-worksheet.mdcompletely. - Run the tests (next section) — all checks must pass.
Tests
bash tests/run_tests.sh
Expected final line: 9 checks, 0 failure(s). The command exits 0 on success
and non-zero on any failure, so it can run in CI. It uses no network.
Cleanup
Nothing to clean up: the scripts write nothing outside their own console
output, and the tests remove their temporary directory automatically. If your
editor stripped the intentional flaws from the sample, restore it with
git checkout -- examples/samples/buggy.sh.
Troubleshooting
See troubleshooting.md for the full list (empty bash -n
output, missing ShellCheck, invisible trailing whitespace, editors that strip
it, permission messages, Windows notes).
Security notes
See security.md. Short version: the scripts only analyze local files (they never run the sample), make no network calls, and need no elevated privileges — modelling the rule to lint and read untrusted code rather than run it.
Extension exercises
- Install ShellCheck (free) and re-run the quality check; look up two SC
codes (e.g.
SC2086,SC2034) and read their explanations. - Fix
buggy.sh: quote the variables, remove or use the unused variable, switch[ ]to[[ ]], and confirm ShellCheck then reports nothing. - Extend the formatting check to also flag lines longer than 100 characters
(
awk 'length > 100'), and add a test for it intests/run_tests.sh.
Navigation
- Previous day: Day 36 — Choosing and Configuring a Code Editor (
labs/sections/computing-foundations/day-036-choosing-and-configuring-a-code-editor/). - Next day: Day 38 — Regular Expressions (
labs/sections/computing-foundations/day-038-regular-expressions/, to be written).
Expected output
FIELDS.md
# Expected output — what to look for (all platforms)
This directory holds real captured runs from the authoring machine
(macOS, Apple Silicon, 2026-07-12, **shellcheck not installed**).
## `quality-check-no-shellcheck.txt`
A real run of `bash examples/quality_check.sh examples/samples/buggy.sh` on a
machine **without** shellcheck. A correct run always shows, in order:
1. `=== Quality check: examples/samples/buggy.sh ===`
2. `[1/3] Syntax check (bash -n)...` → `ok: script is syntactically valid.`
3. `[2/3] Lint check (shellcheck)...` → either
- `SKIP: shellcheck is not installed on this machine.` (as captured here), or
- shellcheck's real findings (SC2086, SC2034, and the test warning) if it *is* installed.
4. `[3/3] Formatting check ...` → two `FAIL` lines: one trailing-whitespace
line (line 13 of the sample) and one tab-indentation line (line 14).
5. `Summary: syntax OK; lint skipped (shellcheck absent); formatting issues found.`
The script **always exits 0** — it is a report, not a gate.
## `tests.txt`
A real run of `bash tests/run_tests.sh`. The final line must read
`9 checks, 0 failure(s).` and the command must exit 0.
## Platform differences (not fabricated — described)
- **With shellcheck installed** (any OS): step [2/3] prints shellcheck's real
findings instead of the SKIP block, and the summary's lint field reads
`findings` (or `clean`) instead of `skipped (shellcheck absent)`. The test
suite's check 6 adapts automatically: it verifies shellcheck ran rather than
that it was skipped. Every other line is identical.
- **Linux**: output is byte-for-byte the same shape; only the absence/presence
of shellcheck changes step [2/3].
- **Windows**: run under WSL or Git Bash; behaviour matches Linux.
quality-check-no-shellcheck.txt
=== Quality check: examples/samples/buggy.sh ===
[1/3] Syntax check (bash -n)...
ok: script is syntactically valid.
[2/3] Lint check (shellcheck)...
SKIP: shellcheck is not installed on this machine.
Install it (free) to catch bugs like:
- SC2086: unquoted $variable may word-split or glob
- SC2034: variable appears unused
- using [ ] where [[ ]] is safer
See requirements/README.md for install instructions.
[3/3] Formatting check (trailing whitespace / tabs)...
FAIL: found 1 line(s) with trailing whitespace.
13:echo "Hi, $name"
FAIL: found 1 line(s) containing tab indentation.
14: echo "all done"
Summary: syntax OK; lint skipped (shellcheck absent); formatting issues found.
tests.txt
Testing the Day 37 quality pipeline ...
ok: buggy sample exists
ok: quality_check.sh exists
ok: bash -n accepts the valid sample
ok: bash -n flags a broken variant
ok: formatting check flags trailing whitespace
ok: formatting check flags tab indentation
ok: quality check exits 0
ok: lint step skips gracefully (shellcheck absent)
ok: clean file passes the whitespace check
9 checks, 0 failure(s).
Source files
examples/quality_check.sh (2941 bytes)
#!/usr/bin/env bash
# quality_check.sh — a tiny, editor-agnostic quality gate for shell scripts.
#
# Runs three checks on a target script and prints a report:
# 1. Syntax check with `bash -n` (the shell's own built-in check).
# 2. Lint with `shellcheck` IF it is installed; otherwise it reports that
# clearly and describes what shellcheck would catch (graceful degrade).
# 3. Formatting check with `grep`: trailing whitespace and tab indentation.
#
# It is a REPORT, not a gate: it always exits 0 so it never blocks your work.
# Usage: bash quality_check.sh [path/to/script.sh]
set -u
target="${1:-examples/samples/buggy.sh}"
if [ ! -f "$target" ]; then
echo "Error: file not found: $target" >&2
echo "Usage: bash quality_check.sh [path/to/script.sh]" >&2
exit 2
fi
tab="$(printf '\t')"
syntax_state="OK"
lint_state="reported"
fmt_state="clean"
echo "=== Quality check: ${target} ==="
echo
# ---- 1. Syntax ------------------------------------------------------------
echo "[1/3] Syntax check (bash -n)..."
syntax_err="$(bash -n "$target" 2>&1)"
if [ -z "$syntax_err" ]; then
echo " ok: script is syntactically valid."
else
echo " FAIL: syntax error(s):"
printf '%s\n' "$syntax_err" | sed 's/^/ /'
syntax_state="errors"
fi
echo
# ---- 2. Lint --------------------------------------------------------------
echo "[2/3] Lint check (shellcheck)..."
if command -v shellcheck >/dev/null 2>&1; then
if shellcheck "$target"; then
echo " ok: shellcheck found no issues."
lint_state="clean"
else
echo " (shellcheck findings above — each SCxxxx code links to an explanation.)"
lint_state="findings"
fi
else
echo " SKIP: shellcheck is not installed on this machine."
echo " Install it (free) to catch bugs like:"
echo " - SC2086: unquoted \$variable may word-split or glob"
echo " - SC2034: variable appears unused"
echo " - using [ ] where [[ ]] is safer"
echo " See requirements/README.md for install instructions."
lint_state="skipped (shellcheck absent)"
fi
echo
# ---- 3. Formatting --------------------------------------------------------
echo "[3/3] Formatting check (trailing whitespace / tabs)..."
ws_hits="$(grep -nE '[[:space:]]+$' "$target" || true)"
tab_hits="$(grep -n "$tab" "$target" || true)"
if [ -n "$ws_hits" ]; then
count="$(printf '%s\n' "$ws_hits" | grep -c .)"
echo " FAIL: found ${count} line(s) with trailing whitespace."
printf '%s\n' "$ws_hits" | sed 's/^/ /'
fmt_state="issues found"
else
echo " ok: no trailing whitespace."
fi
if [ -n "$tab_hits" ]; then
count="$(printf '%s\n' "$tab_hits" | grep -c .)"
echo " FAIL: found ${count} line(s) containing tab indentation."
printf '%s\n' "$tab_hits" | sed 's/^/ /'
fmt_state="issues found"
else
echo " ok: no tab indentation."
fi
echo
echo "Summary: syntax ${syntax_state}; lint ${lint_state}; formatting ${fmt_state}."
exit 0
examples/samples/buggy.sh (352 bytes)
#!/bin/bash
# buggy.sh - a deliberately flawed sample for the Day 37 lab.
# It is syntactically valid (bash -n passes) and it runs, yet a linter
# finds real bugs. Treat it as an exhibit to inspect, not code to trust.
name=$1
unused_greeting="Hello there"
if [ $name = "admin" ]; then
echo "Welcome, admin"
fi
echo "Hi, $name"
echo "all done"
metadata.yml (742 bytes)
lesson_id: D037
day: 37
kind: command-line-inspection
languages: [bash]
setup_commands:
- cd labs/sections/computing-foundations/day-037-debuggers-linters-and-formatters
run_commands:
- bash examples/quality_check.sh examples/samples/buggy.sh
- bash starter/quality_check.sh examples/samples/buggy.sh
test_commands:
- bash tests/run_tests.sh
cleanup_commands:
- 'git checkout -- examples/samples/buggy.sh # optional: restore the intentional flaws if your editor stripped them'
requires_network: false
requires_api_key: false
estimated_minutes: 30
last_executed: '2026-07-12'
executed_on: 'macOS (Apple Silicon), shellcheck NOT installed — bash tests/run_tests.sh → 9 checks, 0 failure(s); lint step degraded gracefully (SKIP)'
requirements/README.md (1367 bytes)
# Dependencies — Day 37 lab
**Required: a POSIX shell only.** The lab runs on tools that ship with your OS:
- `bash` ≥ 3.2 (preinstalled on macOS and every mainstream Linux distribution)
- Standard utilities: `grep`, `sed`, `printf`, `mktemp` — all part of the base system
There is deliberately no `requirements.txt` / `package.json`: the quality
check must run on a factory-fresh machine.
## Optional (recommended): ShellCheck
[ShellCheck](https://www.shellcheck.net/) is a free, open-source linter for
shell scripts. The lab **works without it** — the quality check detects its
absence and reports what it would have caught — but installing it turns the
lint step on and lets you see real findings. It is free and worth having.
Install (all free):
- **macOS (Homebrew):** `brew install shellcheck`
- **Debian / Ubuntu:** `sudo apt install shellcheck`
- **Fedora:** `sudo dnf install ShellCheck`
- **Windows:** install under WSL with the Ubuntu instructions, or use `scoop install shellcheck`
Verify with `shellcheck --version`. After installing, re-run
`bash examples/quality_check.sh examples/samples/buggy.sh` and step [2/3] will
show real SC-code findings instead of the SKIP block.
No account, API key, or network access is required for any part of this lab
(installing ShellCheck is the only step that uses the network, and it is
optional).
starter/quality_check.sh (3018 bytes)
#!/usr/bin/env bash
# quality_check.sh — YOUR working file for the Day 37 lab.
#
# This starter already handles the plumbing: it takes a target script, checks
# the file exists, and prints the report headers. Your job is to fill in the
# four numbered exercises below with the exact command named in each comment.
# The completed reference version is examples/quality_check.sh — try the
# exercises yourself first, then compare.
set -u
target="${1:-examples/samples/buggy.sh}"
if [ ! -f "$target" ]; then
echo "Error: file not found: $target" >&2
echo "Usage: bash quality_check.sh [path/to/script.sh]" >&2
exit 2
fi
tab="$(printf '\t')"
echo "=== Quality check: ${target} ==="
echo
# ---- 1. Syntax ------------------------------------------------------------
echo "[1/3] Syntax check (bash -n)..."
# Exercise 1: capture the output of `bash -n "$target" 2>&1` into syntax_err.
# `bash -n` checks syntax WITHOUT running the script; clean scripts print
# nothing. Replace the empty assignment below with the real command.
syntax_err="" # <-- Exercise 1: syntax_err="$(bash -n "$target" 2>&1)"
if [ -z "$syntax_err" ]; then
echo " ok: script is syntactically valid."
else
echo " FAIL: syntax error(s):"
printf '%s\n' "$syntax_err" | sed 's/^/ /'
fi
echo
# ---- 2. Lint --------------------------------------------------------------
echo "[2/3] Lint check (shellcheck)..."
# Exercise 2: detect shellcheck gracefully. Replace the word 'false' below
# with a real test for the command: command -v shellcheck >/dev/null 2>&1
if false; then # <-- Exercise 2: if command -v shellcheck >/dev/null 2>&1; then
shellcheck "$target" && echo " ok: shellcheck found no issues."
else
echo " SKIP: shellcheck is not installed (or not detected)."
echo " Install it (free) to catch SC2086 (unquoted \$var),"
echo " SC2034 (unused variable), and [ ] vs [[ ]] issues."
echo " See requirements/README.md for install instructions."
fi
echo
# ---- 3. Formatting --------------------------------------------------------
echo "[3/3] Formatting check (trailing whitespace / tabs)..."
# Exercise 3: find trailing whitespace. Replace the empty assignment with:
# grep -nE '[[:space:]]+$' "$target" || true
ws_hits="" # <-- Exercise 3: ws_hits="$(grep -nE '[[:space:]]+$' "$target" || true)"
# Exercise 4: find tab indentation. Replace the empty assignment with:
# grep -n "$tab" "$target" || true
tab_hits="" # <-- Exercise 4: tab_hits="$(grep -n "$tab" "$target" || true)"
if [ -n "$ws_hits" ]; then
echo " FAIL: lines with trailing whitespace:"
printf '%s\n' "$ws_hits" | sed 's/^/ /'
else
echo " ok: no trailing whitespace (or exercise 3 not yet done)."
fi
if [ -n "$tab_hits" ]; then
echo " FAIL: lines containing tab indentation:"
printf '%s\n' "$tab_hits" | sed 's/^/ /'
else
echo " ok: no tab indentation (or exercise 4 not yet done)."
fi
echo
echo "Report complete (this script always exits 0 — it reports, it does not block)."
exit 0
starter/quality-worksheet.md (1842 bytes)
# Quality worksheet — Day 37 lab
Fill this in for `examples/samples/buggy.sh` after running the quality check.
Record real line numbers from the output. Keep this file — it seeds the
Week 6 project (formatting and linting on every commit).
## 1. One issue `bash -n` catches (syntax)
`bash -n` only reports problems the shell cannot even parse. The sample as
shipped is syntactically valid, so to see this check *fire*, introduce a
syntax error on purpose (for example, delete the `fi` on line 11), run
`bash -n examples/samples/buggy.sh`, record the message, then undo the edit.
- Syntax error I introduced: `________________________________`
- What `bash -n` reported (message + line): `________________________________`
## 2. One issue ShellCheck catches — or would (lint / pattern)
If ShellCheck is installed, run it and record a real finding with its SC
code. If it is not installed, describe one bug from the lesson that it
*would* catch (the unquoted `$name` in the `[ ]` test, or the unused
`unused_greeting`).
- Rule code (if you have ShellCheck), e.g. `SC2086` or `SC2034`: `____________`
- The line and what is wrong with it: `________________________________`
- Why running the script does NOT reveal this bug: `____________________`
## 3. One formatting issue (whitespace check)
Run `bash examples/quality_check.sh examples/samples/buggy.sh` and read
section [3/3].
- Line number with trailing whitespace: `______`
- Line number with tab indentation: `______`
## 4. Short paragraph: why "it parses" is not "it's correct"
Write 4–6 sentences, in your own words, explaining why a script can pass the
syntax check (`bash -n`) yet still be full of the bugs a linter finds. Tie it
to the difference between "the shell can parse this" and "this will behave
correctly for every input."
```
(your paragraph here)
```
tests/run_tests.sh (3347 bytes)
#!/usr/bin/env bash
# Tests for the Day 37 lab. Run from the lab directory:
# bash tests/run_tests.sh
#
# Verifies the quality-check pipeline behaves correctly:
# - `bash -n` flags a broken variant of the sample
# - the formatting check flags trailing whitespace in the buggy sample
# - the quality check exits 0 whether or not shellcheck is installed
# (lint is skipped, not failed, when shellcheck is absent)
# No network access is used anywhere.
set -u
lab_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
sample="${lab_dir}/examples/samples/buggy.sh"
checker="${lab_dir}/examples/quality_check.sh"
tmp="$(mktemp -d "${TMPDIR:-/tmp}/day37.XXXXXX")"
trap 'rm -rf "${tmp}"' EXIT
failures=0
checks=0
check() {
local label="$1" ok="$2"
checks=$((checks + 1))
if [ "${ok}" = "yes" ]; then
echo " ok: ${label}"
else
echo " FAIL: ${label}"
failures=$((failures + 1))
fi
}
echo "Testing the Day 37 quality pipeline ..."
# 0. Fixtures exist.
[ -f "${sample}" ] && check "buggy sample exists" "yes" || check "buggy sample exists" "no"
[ -f "${checker}" ] && check "quality_check.sh exists" "yes" || check "quality_check.sh exists" "no"
# 1. The shipped sample is syntactically valid (bash -n exits 0, no output).
if bash -n "${sample}" >/dev/null 2>&1; then
check "bash -n accepts the valid sample" "yes"
else
check "bash -n accepts the valid sample" "no"
fi
# 2. bash -n FLAGS a broken variant (missing 'fi' → parse error, non-zero).
broken="${tmp}/broken.sh"
grep -v '^fi$' "${sample}" > "${broken}"
if bash -n "${broken}" >/dev/null 2>&1; then
check "bash -n flags a broken variant" "no"
else
check "bash -n flags a broken variant" "yes"
fi
# 3. The quality check flags trailing whitespace in the buggy sample.
out="$(bash "${checker}" "${sample}" 2>&1)"
echo "${out}" | grep -q "trailing whitespace" && \
check "formatting check flags trailing whitespace" "yes" || \
check "formatting check flags trailing whitespace" "no"
# 4. The quality check flags the tab-indented line.
echo "${out}" | grep -q "tab indentation" && \
check "formatting check flags tab indentation" "yes" || \
check "formatting check flags tab indentation" "no"
# 5. The quality check exits 0 (report, not gate) regardless of shellcheck.
if bash "${checker}" "${sample}" >/dev/null 2>&1; then
check "quality check exits 0" "yes"
else
check "quality check exits 0" "no"
fi
# 6. Lint is skipped-not-failed when shellcheck is absent; run when present.
if command -v shellcheck >/dev/null 2>&1; then
echo "${out}" | grep -qi "shellcheck" && \
check "lint step runs shellcheck (installed)" "yes" || \
check "lint step runs shellcheck (installed)" "no"
else
echo "${out}" | grep -q "SKIP: shellcheck is not installed" && \
check "lint step skips gracefully (shellcheck absent)" "yes" || \
check "lint step skips gracefully (shellcheck absent)" "no"
fi
# 7. On a clean file, the formatting check reports no issues.
clean="${tmp}/clean.sh"
printf '#!/bin/bash\necho "clean"\n' > "${clean}"
clean_out="$(bash "${checker}" "${clean}" 2>&1)"
echo "${clean_out}" | grep -q "no trailing whitespace" && \
check "clean file passes the whitespace check" "yes" || \
check "clean file passes the whitespace check" "no"
echo
echo "${checks} checks, ${failures} failure(s)."
[ "${failures}" -eq 0 ]
Troubleshooting
Troubleshooting — Day 37 lab
bash -n printed nothing
That is success. bash -n reports only syntax it cannot parse; a valid
script produces no output and exits 0. Confirm with echo $? (it prints 0).
To see the check fire, temporarily introduce a syntax error (delete the
fi on line 11 of the sample), run bash -n, then undo the edit.
shellcheck: command not found
ShellCheck is optional. The quality check detects its absence and prints a
SKIP block describing what it would have caught, then continues. To gain the
lint step, install ShellCheck (free) per requirements/README.md
(brew install shellcheck on macOS, sudo apt install shellcheck on
Debian/Ubuntu), then re-run the quality check.
The formatting check finds nothing on my own script
That means your script has no trailing whitespace or tab indentation — good.
To watch the check fire, add a space at the end of any line and re-run
bash examples/quality_check.sh <your-script>.
Permission denied when running a script
Run it through bash explicitly, e.g. bash examples/quality_check.sh ...,
rather than ./examples/quality_check.sh. If you prefer ./, first make it
executable with chmod +x examples/quality_check.sh.
The trailing-whitespace line looks blank in my terminal
Trailing spaces are invisible by design — that is exactly why the check exists. The line number in the report tells you which line; open it in your editor with "show whitespace" enabled (Day 36 covered this) to see the spaces.
My editor keeps deleting the trailing whitespace in buggy.sh
Many editors strip trailing whitespace on save. If you edit buggy.sh and the
trailing-whitespace finding disappears, that is your editor "helpfully" fixing
it. Restore the sample from git (git checkout -- examples/samples/buggy.sh)
to get the intentional flaws back.
Tests fail with a non-zero exit
Run bash tests/run_tests.sh and read which check says FAIL. Each check
names exactly what it verified (syntax handling, whitespace flagging, exit
code, graceful shellcheck skip). No check needs the network.
Windows: bash is not recognized
Use WSL (wsl --install, then open Ubuntu) or Git Bash, and run the same
commands. Behaviour matches Linux.
Security notes
Security notes — Day 37 lab
- What the scripts do:
quality_check.shandtests/run_tests.shonly read and analyze local files — they runbash -n(a syntax check that parses but does not execute the target),grep, andsed. They make no network connections and change nothing outside their own console output and a temporary directory the tests clean up automatically. - The sample is never executed.
examples/samples/buggy.shis an exhibit to inspect, not to run. The lab deliberately analyzes it statically; it never runs it. This models the real rule below. - Never run untrusted scripts. Static analysis (linting,
bash -n, reading the source) is safe on code you do not trust because it does not execute that code. Running an unread script from the internet is one of the most common ways developers get compromised. Read a script, and lint it, before you ever run it — and neversudoa script you have not read. - Privileges: everything runs as your normal user. Nothing here needs
sudo. The only step that touches the network is the optional ShellCheck install, which you run deliberately from your OS package manager. - Privacy: the scripts expose only what is already in the files you point them at. They collect no system information and send nothing anywhere.