Copyright (c) 2026 MindMesh Academy. All rights reserved. This content is proprietary and may not be reproduced or distributed without permission.

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:
RuleWhy
Always review and test AI-generated code before running itThe AI cannot see your environment; a plausible-looking script may delete the wrong files or open a firewall hole
Validate security configs especially carefullyAn 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 serviceLogs, 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 deployIf 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.

Alvin Varughese
Written byAlvin Varughese
Founder18 professional certifications