Script foundations
Return a useful exit status
Use zero for success, non-zero for failure, and preserve the command result automation needs.
10 minute lesson
Every command finishes with an exit status, a number from 0 to 255. Status zero means success; other values identify a failed or exceptional outcome. Shell automation composes commands through exit status: if, &&, ||, cron, systemd, and CI pipelines all read it. Your script reports one too, whether you thought about it or not.
Read a status
The special parameter $? holds the status of the last command:
ls /etc/hostname
# /etc/hostname
printf '%s\n' "$?"
# 0
ls /nonexistent
# ls: cannot access '/nonexistent': No such file or directory
printf '%s\n' "$?"
# 2
Observe the status with printf '%s\n' "$?" immediately afterward. Any command you run in between — even an innocent echo — replaces it with its own status.
Fail early and clearly
A script should stop with a non-zero status the moment its requirements aren’t met. Check a required command:
if ! command -v curl >/dev/null 2>&1; then
printf '%s\n' 'curl is required' >&2
exit 1
fi
command -v curl succeeds when curl exists on PATH and fails otherwise. We discard its output because only the status matters here. exit 1 makes the failure visible to whatever ran the script.
To verify both paths, run the script normally and with a restricted PATH:
PATH=/nonexistent bash check-tools.sh
# curl is required
printf '%s\n' "$?"
# 1
The trap: exiting zero by accident
Without an explicit exit, a script returns the status of its last command. That rule causes a classic bug:
if ! tar -czf /mnt/backups/site.tar.gz -C /var/www .; then
printf '%s\n' 'backup failed' >&2
fi
# script ends here — printf succeeded, so the script exits 0
The error message went out, but printf was the last command and it succeeded, so the script reports success. Cron marks the job green and nobody looks again for months.
Do not print an error and then accidentally exit zero. Callers trust the status more than human prose — put exit 1 right after the message, every time.
Lesson completed