๐ Debugging Scripts
Debugging shell scripts requires understanding how the shell executes commands, expands variables, handles errors, and manages processes.
This module provides practical techniques for diagnosing issues in POSIXโcompatible scripts.
๐ Who This Is For
- Engineers debugging nonโtrivial shell scripts
- DevOps/SRE teams maintaining CI/CD pipelines
- Developers working with pipelines, subshells, or environment issues
- Anyone needing reliable troubleshooting techniques
๐งฉ Role in the Ecosystem
Debugging tools in POSIX shells are minimal compared to full programming languages.
Effective debugging relies on:
- Tracing execution
- Inspecting variables
- Understanding subshell behavior
- Checking exit codes
- Logging intermediate state
These techniques are essential for writing predictable, productionโgrade automation.
๐งฉ Key Concepts
1. Exit Codes
Every command returns a status:
2. Tracing
Shells can print each executed command:
3. Subshell Isolation
Variables modified in subshells do not persist
(see Subshells).
4. Expansion Debugging
Many bugs come from incorrect quoting or expansion
(see Parameter Expansion).
๐ง Techniques
Enable Tracing
Disable:
Strict Mode (bash/ksh)
Print Debug Messages
| debug() {
printf '[DEBUG] %s\n' "$*" >&2
}
|
Inspect Variables
Check Exit Codes Explicitly
| command
status=$?
echo "exit code: $status"
|
Debug Pipelines
Debug Subshell Behavior
| echo "parent $$"
( echo "subshell $$" )
|
โ ๏ธ Limitations & Pitfalls
set -e behaves inconsistently across shells
- Pipelines hide failures without
pipefail
- Subshells discard variable changes
- Quoting errors often go unnoticed
- Debug output may break scripts expecting clean stdout
๐ง When to Use These Techniques
- Debugging CI/CD failures
- Investigating unexpected variable values
- Understanding pipeline behavior
- Diagnosing environment propagation issues
- Rewriting or refactoring legacy scripts
โ When Not to Use Them
- In production scripts without disabling tracing
- When debugging output must not appear on stderr
- When strict mode breaks legacy behavior
โ
Best Practices
- Use tracing only temporarily
- Log to stderr, not stdout
- Prefer explicit exit code checks
- Use
set -euo pipefail in new bash scripts
- Test under multiple shells (bash, dash, ash, ksh)
- Keep debug helpers small and reusable
๐งช Testing Debugging Behavior
| set -x
x=1
y=$((x + 1))
echo "$y"
|
Test pipeline failures:
| set -o pipefail
false | true
echo $? # 1
|
๐ง Summary
Debugging shell scripts requires deliberate techniques: tracing, inspecting variables, checking exit codes, and understanding subshell behavior.
Used correctly, these tools make shell scripts predictable, maintainable, and productionโready