<aside> 🔍

Module 15 — Debugging, Testing, and Production Scripts. set -x, bats tests, logging, cron quirks, and a full production script — everything from the track assembled into scripts you would actually ship.

🧠 concept → 🧩 analogy → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (hidden)

</aside>

<aside> 📋

Before you start. You need the whole track — this module assembles it. Tools: ShellCheck (installed in Module 14) and bats, the bash test framework: sudo apt install bats (Debian/Ubuntu; other systems: bats-core.readthedocs.io). Keep ~/bash-course.

</aside>

Part A — Debugging: making bash narrate

A1. set -x: the running commentary

<aside> 📖

Official docs: Bash manual — The Set Builtin (-x, -n, -v) · Bash manual — Bash Variables (PS4)

</aside>

set -x (or invoking with bash -x script.sh) makes bash print every command after expansion, before execution, prefixed with +, on stderr. That "after expansion" is the whole value: you see what the command became — variables filled in, quotes resolved, splits performed — which is exactly the layer where twelve modules of bugs live. The prefix is customizable through the variable PS4, and one upgrade earns its place in every toolbox: file-and-line stamps.

export PS4='+ ${BASH_SOURCE##*/}:${LINENO}: '
set -x

Scope tracing like a scalpel, not a floodlight: set -x before the suspect region, set +x after — a 400-line script traced end-to-end is noise, ten traced lines are a diagnosis.

<aside> 🧩

Real-world analogy — the flight data recorder, switched to live. A misbehaving aircraft with a live-narrating recorder — "flaps commanded 15, actual 15; throttle commanded 80, actual 62…" — turns "it feels sluggish" into "throttle disagreement, line 62." set -x is that recorder: not what you wrote, but what the machine actually did with it, in order, timestamped by position.

Where the analogy stops working. Flight recorders are sealed against the crew. Your trace is not sealed against your secrets: set -x prints expanded commands, so curl -H "Authorization: Bearer $TOKEN" writes the token into stderr — and into whatever log captures it. Production rule: set +x around secret-handling regions, always, and treat trace output as sensitive (Module 7's read -rs discipline extends to traces).

</aside>

🧪 Exercise 15.1 — the narrated run

cd ~/bash-course
nano tracedemo.sh    # six lines:
#!/bin/bash
export PS4='+ ${BASH_SOURCE##*/}:${LINENO}: '
set -x
name="Ada"
greeting="Hello, $name"
echo "$greeting"
chmod +x tracedemo.sh
./tracedemo.sh

A2. bash -n: the parse-only pass, and the debugging ladder

<aside> 📖

Official docs: Bash manual — The Set Builtin · ShellCheck

</aside>

bash -n script.sh parses without executing: syntax errors (the unclosed if, the missing fi) surface instantly, with zero commands run — the only completely safe check you can give an untrusted or half-edited script. (bash -v echoes lines as read, pre-expansion — occasionally useful for spotting what bash even sees; -x remains the workhorse.) The professional ladder, cheapest rung first: ShellCheck (static, catches whole bug classes before any run) → bash -n (parses?) → probe prints (printf '[%s]\n' at the suspect value — Module 2) → scoped set -x (narrate the suspect region) → bats (Part B: pin the fix so it stays fixed).

🧪 Exercise 15.2 — catch a syntax error without running anything

The file is broken on purpose.