How to return exit status codes in Bash

Bash scripts frequently utilize exit codes to communicate their execution status. These codes are numerical values returned by commands upon completion, signifying success, failure, or specific error conditions.

Here's a breakdown of exit codes in Bash:

Exit code 0

This indicates successful execution. The command ran flawlessly and achieved its intended outcome.

Non-zero exit codes

These signify various non-successful scenarios. Common examples include:

  1. 1: General error (often due to syntax errors or missing files)
  2. 2: Invalid command or argument
  3. 127: Command not found
  4. 137: Kill signal received

Beyond generic codes, individual programs often define specific exit codes to convey precise error details. You can find these documented in the respective program's manual pages.

The special shell variable $?

To check the exit code of a command in Bash, you can use the special variable $?. After executing a command, you can immediately check its exit code by examining the value of $?.

#!/bin/bash ls non-existent-directory if [ $? -eq 0 ]; then echo "Command succeeded" else echo "Command failed with exit code $?" fi

In this example, the ls command is used to list the contents of a non-existent directory. After executing the command, the script checks the exit code using $?. If the exit code is 0, it prints "Command succeeded"; otherwise, it prints "Command failed with exit code $?".

You can also check the exit code directly in conditional statements without using $?. For example:

#!/bin/bash if ls non-existent-directory; then echo "Command succeeded" else echo "Command failed with exit code $?" fi

In this case, the if statement directly evaluates the exit code of the ls command. If the exit code is 0, it considers the command successful, and if it's non-zero, it considers the command failed.

Using exit command

The exit command is used to terminate the script's execution immediately. The exit command takes an optional numeric argument, which represents the exit code. This exit code is then returned to the calling environment, allowing other scripts or processes to determine whether the script completed successfully or encountered an error.

Here's an example script to illustrate the use of the exit command:

#!/bin/bash echo "This is a script that demonstrates the exit command." # Perform some tasks echo "Task 1: Performing some operation..." # Assume an error occurred during Task 1 echo "Task 1 failed. Exiting script with exit code 1." exit 1 # The following code won't be executed because the script has already exited echo "Task 2: This won't be printed."
In this script:

The script begins by printing a message, then performs Task 1. Encountering an error, it exits using exit 1, signaling a non-zero exit code for failure. Subsequent code is skipped as the script terminates. Execution prints the initial message and initiates Task 1, but exits promptly with a code of 1 due to the encountered error. Task 2's message is omitted as the script has concluded.

You can check the exit code of a script using the $? variable in the calling environment. For example, if you run the script and then check the exit code:

./example_script.sh echo "Exit code: $?"

The value printed for the exit code will be 1, indicating that the script exited with an error. This mechanism allows other scripts or processes to determine the success or failure of the executed script.

What happens if I don’t specify an exit code

If you don't specify an exit code with the exit command in a Bash script, it defaults to the status of the last executed command. If the last command succeeds, the exit code is 0, indicating success. If it fails, the exit code is non-zero, signaling an error.

Best practices

When checking exit codes in Bash, consider the following best practices:

Use $? Immediately

After executing a command, check its exit code using $? immediately. Storing it in a variable ensures it is not overwritten by subsequent commands.

Use Conditional Statements

Instead of explicitly checking $?, use conditional statements directly. For example:

if command; then echo "Command succeeded" else echo "Command failed with exit code $?" fi

Check for Specific Exit Codes

Consider specific exit codes for different scenarios. Conventionally, 0 signifies success; non-zero values indicate errors. Document and adhere to these conventions.

Handle Errors Appropriately

Implement error handling based on exit codes. Exit the script on critical errors using exit, providing a clear indication of failure.

Logging

Log relevant information about the command execution and exit codes. This aids in debugging and analyzing script behavior.

Use set -e with Caution

set -e makes the script exit immediately if any command exits with a non-zero status. While it can simplify error handling, it may lead to unexpected behavior, so use it wisely.

Consider trap for Cleanup

Use trap to set up cleanup operations that ensure resources are released even if the script exits prematurely.

Example incorporating some of these practices:

#!/bin/bash set -e # Exit on any command failure # Function to handle cleanup cleanup() { echo "Cleaning up..." # Add cleanup logic here } # Trap to call cleanup on script exit trap cleanup EXIT # Execute a command if result=$(some_command); then echo "Command succeeded: $result" else echo "Command failed with exit code $?" exit 1 # Exit script on failure fi # Continue script execution echo "Continue with the rest of the script."

Adhering to these best practices enhances the robustness and maintainability of Bash scripts.

Conclusion

When checking exit codes in Bash, it is best practice to immediately use $? after executing a command, employ conditional statements for clarity, and handle errors appropriately based on exit codes. Adhering to specific conventions, logging, and sensibly using features like set -e contribute to robust and maintainable Bash scripts.