Bash Exit Command and Exit Codes

By 

Updated on

7 min read

Bash exit command and exit codes in a shell script

Often when writing Bash scripts, you will need to terminate the script when a certain condition is met or take action based on the exit code of a command.

This article covers the Bash exit built-in command and the exit statuses of executed commands.

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:

Terminal
date &> /dev/null
echo $?

The date command completed successfully, so the exit code is zero:

output
0

If you try to run ls on a nonexistent directory, the exit code will be non-zero:

Terminal
ls /nonexistent_dir &> /dev/null
echo $?
output
2

Each 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:

Terminal
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:

Terminal
sudo tcpdump -n -l | tee file.out
echo "${PIPESTATUS[0]}"  # exit code of tcpdump
echo "${PIPESTATUS[1]}"  # exit code of tee

Bash exit Command

The exit command exits the shell with a given status:

txt
exit N

If 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:

CodeMeaning
0Success
1General error
2Misuse of a shell built-in (wrong arguments, etc.)
126Command found but not executable (permission issue)
127Command not found
128Invalid argument passed to exit
128+NScript terminated by signal N (e.g., 130 = Ctrl+C, 137 = SIGKILL)

Using meaningful exit codes in your scripts makes it easier for callers — 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:

sh
if grep -q "search-string" filename; then
  echo "String found."
else
  echo "String not found."
fi

When 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:

Terminal
cd /opt/code && mkdir project

With ||, the second command runs only if the first fails:

Terminal
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:

~/script.shsh
#!/bin/bash

echo "doing stuff..."

exit

Using 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:

~/check-root.shsh
#!/bin/bash

if [[ $EUID -ne 0 ]]; then
  echo "Only user root can run this script."
  exit 1
fi

echo "doing stuff..."

exit 0

If 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 immediately on any non-zero exit code, add set -e at the top:

~/script.shsh
#!/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:

~/script.shsh
#!/bin/bash
set -e
set -o pipefail

grep "ERROR" app.log | sort | uniq -c

Without 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.

exit vs return in Functions

Inside a Bash function , exit terminates the entire script, not just the function. To exit only the function and return control to the caller, use return:

sh
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. 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 / VariableDescription
exit NExit shell or script with status N
exitExit with status of last command
$?Exit status of the last command
${PIPESTATUS[@]}Exit codes of all commands in last pipeline
set -eExit script immediately on any error
set -o pipefailPropagate pipeline failures to $?
return NExit 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 exit code of the first failing command. 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 make it exit immediately when any command returns a non-zero exit code.

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 any command fails? Add set -e at the top of your script. For pipelines, also add set -o pipefail to catch failures in intermediate pipeline commands.

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, 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 to make your scripts fail fast on errors. Inside functions, use return instead of exit to avoid terminating the entire script unintentionally.

If you have any questions, feel free to leave a comment below.

Tags

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

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