Bash Exit Command and Exit Codes

Whether you are closing an interactive terminal session or writing a script that must stop when a certain condition is met, the Bash exit command is how you end a shell and return a status to whatever started it.
This article covers the Bash exit built-in command and the exit statuses of executed commands.
Exiting the Bash Shell
To close an interactive Bash session, type exit and press Enter:
exitYou can also press Ctrl+D at an empty prompt. This tells Bash that it has reached end-of-file (EOF) on standard input, so it exits unless the ignoreeof shell option is enabled. If the current shell is a login shell, the logout command does the same thing.
The session closes with the exit status of the last command that ran. To exit with a specific status, pass it as an argument, such as exit 0.
Exit Status
Each shell command returns an exit code when it terminates, whether successfully or not.
By convention, an exit code of zero indicates the command completed successfully, and a non-zero value means an error was encountered.
The special variable $? holds the exit status of the last executed command:
date &> /dev/null
echo $?The date
command completed successfully, so the exit code is zero:
0If you try to run ls on a nonexistent directory, the exit code will be non-zero:
ls /nonexistent_dir &> /dev/null
echo $?2Each command’s man page documents its possible exit codes and what they mean.
When executing a multi-command pipeline, the exit status of the pipeline is that of the last command:
sudo tcpdump -n -l | tee file.out
echo $?This example uses sudo because tcpdump often requires elevated privileges, and it keeps running until you stop it (for example, with Ctrl+C).
In the example above, echo $? prints the exit code of the tee
command. To capture the exit code of every command in a pipeline, use the $PIPESTATUS array:
sudo tcpdump -n -l | tee file.out
statuses=("${PIPESTATUS[@]}")
echo "${statuses[0]}" # exit code of tcpdump
echo "${statuses[1]}" # exit code of teeSave the array immediately after the pipeline. Running another command first, including echo, replaces the values in PIPESTATUS.
Bash exit Command
The exit command exits the shell with a given status:
exit NIf N is not given, the exit status is that of the last executed command.
When used in shell scripts, the value supplied to exit is returned to the shell as the exit code.
Exit Code Conventions
While any value from 0 to 255 is valid, the following codes have well-established meanings:
| Code | Meaning |
|---|---|
0 | Success |
1 | General error |
2 | Misuse of a shell built-in (wrong arguments, etc.) |
126 | Command found but not executable (permission issue) |
127 | Command not found |
128+N | Command terminated by signal N (for example, 130 = Ctrl+C and 137 = SIGKILL) |
Using meaningful exit codes in your scripts makes it easier for callers, such as other scripts, CI pipelines, or monitoring tools, to handle failures correctly.
Using Exit Codes in Scripts
Exit status can be used in conditional commands such as if
. In the following example, grep exits with zero (true in shell scripting) if the string is found:
if grep -q "search-string" filename; then
echo "String found."
else
echo "String not found."
fiWhen running commands separated by && (AND) or || (OR), the exit status determines whether the next command runs. The mkdir
command below runs only if cd succeeds:
cd /opt/code && mkdir projectWith ||, the second command runs only if the first fails:
cd /opt/code || echo "Directory not found"If a script ends with exit without a parameter, the script exit code is that of the last command executed:
#!/bin/bash
echo "doing stuff..."
exitUsing exit alone is equivalent to exit $? or simply omitting the exit.
Here is an example showing how to terminate the script if invoked by a non-root user:
#!/bin/bash
if [[ $EUID -ne 0 ]]; then
echo "Only user root can run this script."
exit 1
fi
echo "doing stuff..."
exit 0If you run the script as root, the exit code will be zero. Otherwise, the script exits with status 1.
Automatic Exit on Error
By default, Bash continues executing a script even when a command fails. To make the script exit after many unhandled command failures, add set -e at the top:
#!/bin/bash
set -e
cp config.txt /etc/myapp/
echo "Config copied successfully."If cp fails, the script stops immediately without running the echo line.
set -e has exceptions in conditionals, command lists, and subshell contexts, so test your script paths carefully rather than relying on it as the only error-handling strategy.
To also catch failures inside pipelines, combine set -e with set -o pipefail:
#!/bin/bash
set -e
set -o pipefail
grep "ERROR" app.log | sort | uniq -cWithout pipefail, a failure in grep would be masked by the exit codes of sort and uniq. With pipefail, the pipeline fails if any command in it fails.
For a full walkthrough of set -e, set -u, set -o pipefail, and IFS, see Bash strict mode
.
exit vs return in Functions and Sourced Scripts
Inside a Bash function
, exit terminates the shell running the function, which normally ends the entire script. In a sourced file, exit can terminate the current interactive shell. To leave only the function or sourced file and return control to the caller, use return:
check_file () {
if [[ ! -f "$1" ]]; then
echo "File not found: $1"
return 1
fi
echo "File exists: $1"
return 0
}
check_file "/etc/hosts"
echo "Exit code: $?"return without an argument returns the exit code of the last command in the function or sourced file. Using exit inside a function is valid when you intentionally want to stop the entire script on a condition.
Quick Reference
For a printable quick reference, see the Bash cheatsheet .
| Command / Variable | Description |
|---|---|
exit N | Exit shell or script with status N |
exit | Exit with status of last command |
$? | Exit status of the last command |
${PIPESTATUS[@]} | Exit codes of all commands in last pipeline |
set -e | Exit on many unhandled command failures, with documented exceptions |
set -o pipefail | Propagate pipeline failures to $? |
return N | Exit a function with status N |
Troubleshooting
$? always shows 0 even after a failing command
You are likely reading $? after an intermediate command such as echo or a variable assignment, which reset it. Capture $? immediately after the command you want to check: cmd; status=$?.
Pipeline exit code does not reflect the failing command
By default, $? captures only the last command in a pipeline. Use set -o pipefail so that the pipeline returns the status of the rightmost command that exits with a non-zero status. Alternatively, inspect individual codes with ${PIPESTATUS[@]}.
Script continues running after a command fails
Bash does not stop on errors by default. Add set -e at the top of the script to stop after many unhandled command failures. Because set -e has exceptions, use explicit conditionals when the handling must be predictable.
FAQ
What does exit code 127 mean?
Exit code 127 means the command was not found. This usually indicates a typo in the command name, a missing PATH entry, or a program that is not installed.
What is the difference between exit and return in a function?exit terminates the entire script regardless of where it is called. return exits only the current function and returns control to the caller. Use return inside functions and exit at the script level.
How do I exit a script automatically when a command fails?
Add set -e at the top of your script to exit after many unhandled command failures. For pipelines, also add set -o pipefail to catch failures in intermediate pipeline commands. Review the documented set -e exceptions when you need predictable error handling.
Can I pass any number to exit?
Valid exit codes are integers from 0 to 255. Values above 255 wrap around (256 becomes 0). Non-integer values produce an error. Stick to 0 for success and small positive integers for specific error conditions.
How do I check the exit code of a command without using $??
You can test the exit code directly in an if statement: if command; then ... fi. The if statement evaluates the command’s exit code: zero means the then branch runs, while non-zero runs the else branch.
Conclusion
Every command in Bash returns an exit code. Use $? to check it, exit N to set it explicitly, and set -e when you want scripts to stop after unhandled failures. Inside functions and sourced files, use return when control should go back to the caller.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page