5.1.2. Input Handling, Error Handling, and Debugging
💡 First Principle: A robust script anticipates failure. Every command can fail; every input can be invalid. Defensive scripting means: validate inputs before acting on them, check return codes, provide meaningful error messages, and clean up on exit. Scripts that fail silently cause the worst kind of production incidents — the kind where the problem isn't discovered until the damage is already done.
Input Handling:
# Positional arguments with validation
if [[ $# -lt 2 ]]; then
echo "Usage: $0 <source> <destination>" >&2
exit 1
fi
SOURCE="$1"
DEST="$2"
# getopts — option parsing
while getopts ":hvf:o:" opt; do # Leading colon = silent mode, so OPTARG holds the bad option in the ?) branch
case "$opt" in
h) usage; exit 0 ;;
v) VERBOSE=true ;;
f) FILE="$OPTARG" ;;
o) OUTPUT="$OPTARG" ;;
?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1)) # Remove parsed options, leave remaining args
# read — interactive input
read -p "Enter username: " USERNAME
read -sp "Enter password: " PASSWORD # -s = silent (no echo)
echo # Print newline after silent read
Error Handling:
# Trap — run cleanup on exit or signals
cleanup() {
echo "Cleaning up..."
rm -f /tmp/myapp_lock
}
trap cleanup EXIT # Run cleanup on any exit
trap cleanup EXIT INT TERM # Also on Ctrl+C and SIGTERM
# Exit codes — use meaningful values
EXIT_OK=0
EXIT_USAGE=1
EXIT_DEPENDENCY=2
EXIT_PERMISSION=3
# Check command success
if ! cp "$SOURCE" "$DEST"; then
echo "ERROR: Failed to copy $SOURCE to $DEST" >&2
exit 1
fi
# Or use || shorthand
mkdir -p "$TMPDIR" || { echo "Cannot create temp dir" >&2; exit 1; }
# Logging function
log() {
local LEVEL="$1"
shift
echo "[$(date '+%Y-%m-%dT%H:%M:%S')] [$LEVEL] $*" | tee -a /var/log/myapp.log
}
log INFO "Starting backup"
log ERROR "Failed to connect to server"
Debugging:
bash -x script.sh # Run with xtrace (print each command before executing)
bash -n script.sh # Syntax check only (no execution)
bash -v script.sh # Print script lines as read
# Enable within script
set -x # Enable xtrace from this point
set +x # Disable xtrace
# Debugging a specific section
set -x
critical_section
set +x
# PS4 — customize xtrace prefix
export PS4='+(${BASH_SOURCE}:${LINENO}): ' # Shows file and line number
Exit Code Best Practices:
# Always exit with explicit code
exit 0 # Success
exit 1 # General error
exit 2 # Misuse of shell built-in
# Check exit code of last command
if [[ $? -ne 0 ]]; then
echo "Command failed"
fi
# Better — check inline
command && echo "Success" || echo "Failed"
⚠️ Exam Trap: Error messages should go to stderr (>&2), not stdout. This allows callers to pipe stdout for data while separately handling errors. echo "Error: $msg" >&2 is correct. Writing errors to stdout corrupts the output when the script's stdout is piped to another command or captured in a variable.
AI-Assisted Administration: Best Practices
💡 First Principle: AI code assistants are accelerators, not authorities. They excel at producing a first draft — boilerplate scripts, regular expressions, config snippets, and explanations of unfamiliar commands — but the administrator remains fully responsible for reviewing, testing, and understanding every line before it runs on a real system.
Where AI is most reliable: well-documented, common tasks with abundant public examples — generating a starter bash or Python script, writing a regex, translating a command between distributions, or explaining what an unfamiliar option does. Where it is least reliable: novel or environment-specific problems, security-critical configuration, and anything depending on facts newer than its training data — it produces confident but wrong output ("hallucinations").
The non-negotiable rules:
| Rule | Why |
|---|---|
| Always review and test AI-generated code before running it | The AI cannot see your environment; a plausible-looking script may delete the wrong files or open a firewall hole |
| Validate security configs especially carefully | An AI-generated iptables ruleset or sudoers entry can silently create an exposure — verify every rule against intent |
| Never paste sensitive data into a public AI service | Logs, keys, passwords, internal IPs, and proprietary configs sent to a public model may be retained or used for training — a data-governance breach. Use approved/private tooling or redact first |
| Understand before you deploy | If you cannot explain what a generated line does, you cannot own the outcome when it fails |
Prompt engineering — giving the model specific context (the distribution, the goal, constraints, and example input/output) yields far better results than a vague request. But a better prompt never removes the review step.
⚠️ Exam Trap: The appropriate role of AI is to assist and accelerate a skilled administrator who validates the output — not to make production changes autonomously or to be trusted blindly. Private or sensitive data must never be sent to a public AI service.
Reflection Question: Write a bash function named require_root that exits with code 1 and an appropriate stderr message if the script is not running as root. Show how to call it at the top of a script.