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.

IdiomMeaning
cmd && echo okrun 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).