In Bash, exit codes (also known as return codes or status codes) are numeric values returned by executed commands or scripts to indicate the result of their execution.
These exit codes are often used to determine the success or failure of a command or script, allowing other parts of a program or script to make decisions based on the outcome of the executed command.
In most programming environments and systems, including Bash, exit statuses are represented using 8 bits, which allows for values from 0 to 255. Here are some common exit codes and their meanings:
Code | Meaning |
---|---|
0 | Success. The command or script executed without any error. |
1 | General error. The command or script failed for some unspecified reason. |
2 | Misuse of shell builtins. The command or script used a shell builtin incorrectly, such as passing an invalid option. |
126 | Command invoked cannot execute. The command or script is found but is not executable, such as lacking permissions or being a directory. |
127 | Command not found. The command or script is not found in the PATH variable. |
128 | Invalid argument to exit. The command or script tried to exit with an invalid argument, such as a negative number or a non-integer. |
128+N | Fatal error signal N. The command or script was terminated by a signal N, where N is a positive integer from 1 to 31. For example, 130 means the command was terminated by Ctrl-C (SIGINT), and 139 means the command was terminated by a segmentation fault (SIGSEGV). |
255 | Exit status out of range. The command or script tried to exit with a value greater than 255. |
Please note that while these exit codes are commonly used, the specific meanings might vary depending on the context and the application or tool you’re using.
If you try to return an exit status outside the 0-255 range, it will be truncated to 8 bits. For example, if you return 256, it will be interpreted as 0, since 256 mod 256 is 0. Similarly, if you return -1, it will be interpreted as 255, since -1 mod 256 is 255.
This can cause unexpected behavior and errors in your scripts. Therefore, it is recommended to only use values from 0 to 125 for normal exit codes, and reserve values above 128 for special cases such as signals or errors.
$?
The special shell variable $?
in bash is used to get the exit status of the last command or the most recently executed process. You can use the $?
variable to check if a command executed successfully or not, and take appropriate actions based on the result.
#!/bin/bash
# Try to copy a file that does not exist
cp foo.txt bar.txt
# Check the exit status of the cp command
if [ $? -eq 0 ]; then
echo "Copy successful"
else
echo "Copy failed"
fi
# Output:
# cp: foo.txt: No such file or directory
# Copy failed
The cp command failed because foo.txt
does not exist, and it returned a non-zero exit status, which was stored in the $?
variable. The if statement then checked the value of $?
and printed the corresponding message.
You can also use the $?
variable in the terminal to check the exit status of any command you run interactively.
$ cat foo.txt
cat: foo.txt: No such file or directory
$ echo $?
1
exit
commandCalling the exit
command within a script will terminate the script’s execution immediately. The exit
command is used to indicate that the script should exit, and you can provide an optional exit status as an argument to indicate the reason for the exit.
Here’s the basic syntax of the exit
command in a Bash script:
exit [exit_status]
exit
without providing an exit status, the script will exit with a status of 0, indicating successful execution.#!/bin/bash
if [[ "$(whoami)" != root ]]; then
echo "Only user root can run this script."
exit 1
fi
echo "doing stuff..."
exit 0
Remember that when the script exits, the exit status is usually available in the special variable $?
, which can be used to capture the exit status of the script for further processing if needed.
exit
or return
inside a functionUsing exit
inside a function will terminate the script, regardless of whether the script is sourced or executed. This is because exit
causes the shell to terminate with the specified status. Therefore, it is not recommended to use exit
inside a function unless you want to end the entire script.
A better alternative is to use return
inside a function, which causes the function or sourced script to exit with the specified status. This way, you can control the flow of your script without terminating it abruptly.
For example, consider the following script, which ends after calling exit
inside myfunc
, and the last echo
statement is not executed.
#!/bin/bash
myfunc() {
echo "Inside myfunc"
exit 1 # this will terminate the script
}
echo "Before calling myfunc"
myfunc
echo "After calling myfunc" # this will not be executed
# Output:
# Before calling myfunc
# Inside myfunc
However, if you change exit
to return
in myfunc, you will see the script continues after returning from myfunc
, and the last echo
statement is executed.
#!/bin/bash
myfunc() {
echo "Inside myfunc"
return 1
}
echo "Before calling myfunc"
myfunc
echo "After calling myfunc"
# Output:
# Before calling myfunc
# Inside myfunc
# After calling myfunc
&&
and ||
operatorsThe &&
and ||
operators are used to combine commands and execute them conditionally based on the exit status of the previous command.
The &&
operator is used to execute the second command only if the first command succeeds (returns zero). For example, you can use it to run a backup command only if a test command passes:
# This will create a compressed archive of data.txt only if the file exists.
test -f data.txt && tar czvf data.tar.gz data.txt
The ||
operator is used to execute the second command only if the first command fails (returns non-zero). For example, you can use it to print an error message only if a copy command fails:
# This will copy source.txt to destination.txt and print "Copy failed"
# only if the copy command returns a non-zero exit status.
cp source.txt destination.txt || echo "Copy failed"
You can also combine the &&
and ||
operators to create more complex conditional commands. For example, you can use them to run a cleanup command only if both a download and an install command succeed:
# This will download, unzip, and delete file.zip only if all three commands return zero.
wget http://example.com/file.zip && unzip file.zip && rm file.zip
Checking the exit status of every command, using the special variable $?
, which stores the exit status of the last executed command or script. For example, you can use an if statement to check if a command succeeded or failed and take appropriate actions based on the result:
# Run a command
some_command
# Check the exit status
if [ $? -eq 0 ]; then
# Command succeeded
echo "Command succeeded"
else
# Command failed
echo "Command failed"
fi
Handling errors gracefully, using the trap
command, which allows you to execute a command or a function when a signal is received by the shell. For example, you can use the trap
command to perform some cleanup actions before the shell exits, regardless of the exit status:
# Trap the EXIT signal and call a function
trap cleanup EXIT
# Define a function to delete a temporary file and print a message
cleanup() {
rm -f temp.txt
echo "Bye"
}
Using standard exit codes when possible, which are reserved by Bash and have special meanings. For example, an exit code of 0 means success, an exit code of 1 means general error, an exit code of 2 means misuse of shell builtins, and so on.
Using custom exit codes sparingly, which are defined by you and can have any value from 0 to 255. You should avoid using values that conflict with the standard exit codes or with other commands or scripts that may use them. You should also document your custom exit codes and their meanings for future reference.
Using clear and descriptive error messages, which can help you and others understand what went wrong and how to fix it. You should print your error messages to the standard error stream (stderr) using the >&2
redirection operator.
# Print an error message to stderr
echo "Invalid argument" >&2
# Exit with a custom code
exit 10