Exit Codes & Debugging
Exit Codes
Every command that finishes running reports back a single number called its exit status (or exit code) - this is the mechanism [ ], &&, ||, and if all quietly rely on behind the scenes throughout this module. By convention, 0 means success, and any non-zero value means some kind of failure, with the specific non-zero value often hinting at what went wrong.
if ! command -v git >/dev/null; then
echo 'git missing' >&2
exit 1
fi
command -v git succeeds (exit 0) if git is found on the PATH, and fails otherwise - the ! in front of it inverts that, so the if block runs specifically when git is missing. Writing to >&2 (stderr) rather than plain echo follows the redirection module's convention: error messages belong on the error stream, not mixed into normal output. The script's own exit 1 is how it deliberately reports "I failed" to whatever called it - without this, a script could silently exit with the misleading success code left over from an unrelated earlier command.
| Idiom | Meaning | ||
|---|---|---|---|
cmd && echo ok | run echo only if cmd succeeded | ||
| `cmd \ | \ | echo fail` | run echo only if cmd failed |
cmd; echo $? | print last exit code |
$? (from the variables table earlier in this module) holds the exit status of whatever command ran immediately before it - check it right away, because it gets overwritten by the very next command you run, including an accidental one.
Debugging: run with bash -x script.sh or add set -x inside the script to have bash print every command it executes, with variables already substituted, right before running it - invaluable for seeing exactly what a script is actually doing versus what you assumed it would do.
Tip: A handful of exit codes carry conventional meanings worth recognizing on sight rather than looking up every time: 1-125 are generally script- or command-specific errors (the exact meaning depends on the program), 126 means the file was found but isn't executable (a permissions problem - see the Scripting Basics section), 127 means the command wasn't found at all (often a typo or a missing PATH entry), and 130 means the process was killed by Ctrl+C - specifically 128 plus the signal number for SIGINT (2), a pattern that extends to any signal-killed process (128 + signal number).