Exit Codes and Checking $? Correctly
In this page:
Reading $? Immediately
$? holds the exit status of the last command that ran, and it is overwritten the instant another command runs, including something as innocuous as echo. Capture it into a variable right away if you need it later.
Example: Reading $? Immediately
#!/bin/bash
true
status=$?
echo "true exited with: $status"
false
status=$?
echo "false exited with: $status"
Login to try C/C++/Java/PHP code in the editor
Testing a Command Directly
Rather than running a command and then inspecting $?, it's simpler and safer to put the command straight inside an if or while condition, since bash evaluates its exit status automatically.
Example: Testing a Command Directly
#!/bin/bash
if grep -q "root" <<< "root:x:0:0"; then
echo "pattern matched, no need to check \$? separately"
fi
Login to try C/C++/Java/PHP code in the editor
Setting a Script's Own Exit Code
exit N immediately stops the script and sets its exit status to N, which any caller (another script, or the shell) can check afterward. Falling off the end of a script without an explicit exit uses the last command's status.
Example: Setting a Script's Own Exit Code
#!/bin/bash
check_even() {
if (( $1 % 2 == 0 )); then
return 0
else
return 1
fi
}
if check_even 4; then
echo "4 is even"
fi
if ! check_even 5; then
echo "5 is not even"
fi
Login to try C/C++/Java/PHP code in the editor
Exit Codes Beyond 0 and 1
Exit codes can be any value from 0 to 255, and many real tools use specific numbers to mean specific things (for example, grep uses 2 to mean an actual error occurred, distinct from 1 meaning "no match found").
Example: Exit Codes Beyond 0 and 1
#!/bin/bash
grep "x" /no/such/file 2>/dev/null
ecode=$?
if [[ $ecode -eq 2 ]]; then
echo "grep reported an error (code 2), not just a non-match"
fi
Login to try C/C++/Java/PHP code in the editor
- Running another command between the one you care about and checking
$?, which overwrites$?with the new command's own status. - Assuming a non-zero exit code always means 0/1 only; commands can return any value 0-255, each with tool-specific meaning.
- Using
$?to check success inside anifwhen you could just put the command directly in theifcondition, which is simpler and avoids the overwrite trap entirely.
- Exit code 0 means success; any non-zero value (1-255) means some kind of failure, with meaning specific to the command.
$?holds the exit status of the most recently executed command and is overwritten by every subsequent command.- Put a command directly inside
if/whileconditions rather than checking$?afterward, when possible. exit Ninside a script sets that script's own exit code, which its caller can then check.
Chapter Quiz — Complete all 12 topics to unlock
0/12 topics done
Complete these topics first:
- Exit Codes and Checking $? Correctly
- set -e and set -u
- Error Handling
- set -e (Exit on Error) and Its Gotchas
- Logging
- set -u (Undefined Variables) and set -x (Trace Mode)
- Script Arguments with getopts
- trap ERR for Custom Error Handling
- Debug Mode (set -x)
- Writing a Custom Error/die Function
- Portability
- Validating Script Input and Arguments