What are exit codes and how is $? used?
Every command returns an exit code: 0 means success, anything 1–255 means failure. $? holds the last command's exit code.
This is the bedrock of shell control flow — if, &&, and || all decide what to do based on exit codes, not on output. The convention (0 = success) is the opposite of most programming languages' boolean, so it's worth burning in: zero is good news. Different non-zero values can signal different errors (e.g. grep returns 1 for "no match" but 2 for an actual error).
The crucial gotcha: $? is overwritten by the very next command, so capture it immediately if you need it later:
grep "pattern" file.txt
result=$? # save it now...
echo "checking..." # ...because this line just reset $? to 0
if [ "$result" -eq 0 ]; then echo "found"; fi
Check exit code with $?:
ls /nonexistent
echo $? # Output: 2 (file not found)
ls /tmp
echo $? # Output: 0 (success)
Use in scripts:
#!/bin/bash
grep "pattern" file.txt
if [ $? -eq 0 ]; then
echo "Pattern found"
else
echo "Pattern not found"
fi
Set exit code in your script:
#!/bin/bash
if [ ! -f "$1" ]; then
echo "File not found" >&2
exit 1
fi
exit 0
Tip: Always check $? immediately - it's overwritten by the next command!