Bash Error Handling

LINUX
FUNDAMENTALS
A Complete Guide for Beginners Enroll Course Now

To build robust and reliable automation, error handling in bash scripts is essential. Without proper error handling a script may continue to run even after an error has occurred resulting in unexpected output or even system crashes.

To handle errors in a script, you can use the methods given below depending on the need:

  1. Use set -e selectively: makes the script exit immediately if any command it runs exits with a non-zero status
  2. Check Command Exit Codes: check its return code using $? and take appropriate actions based on the result.
  3. Use Conditional Execution (|| with True Command): Allow to continue the script execution despite encountering errors.
  4. Trap Errors with trap command: catch errors using signals, such as ERR, and define custom error-handling functions.

These various error-handling techniques work together to protect Bash scripts from unexpected issues, enabling you to build automation that doesn’t just run smoothly but also handles errors gracefully. To assist you, this article will discuss error handling in bash script elaborately. So let’s start!

Understanding the Importance of Error Handling in Bash

In any programming language, errors are inevitable. Errors can be caused by a variety of things, such as incorrect user input, incorrect data formats, and unexpected system conditions. If you don’t have proper error handling in place, you could end up with script errors, data corruption, and even system crashes.

The purpose of error handling in Bash is to:

  1. Improve Script Reliability: Catch and handle errors correctly so that scripts do not crash or terminate suddenly.
  2. Provide Effective Error Management: If an error occurs, you can display informative error messages that explain the error and provide guidance on how to fix it. This improves the user experience and avoids confusion.
  3. Protect Data Integrity: Unhandled errors may cause data corruption or loss, so error handling helps to protect data integrity by not allowing scripts to modify or delete data.
  4. Improve Debugging Efficiency: Error handling allows you to log error messages and related information, making debugging and troubleshooting easier. You can quickly find out where errors are coming from and take corrective actions.

Common Types of Errors in Bash Scripts

Several types of errors can occur in bash scripts. Each type has its characteristics and consequences. Here are some of the most common types of errors in bash scripts:

  1. Syntactical Errors: These errors are caused by incorrect syntax in the bash code. For example, missing keywords, incorrect punctuation, or incorrect command structure can lead to syntax errors.
  2. Runtime Errors: This type of error occurs during the execution of the script. It can be caused by unexpected conditions or by an invalid input. Common types of runtime errors in bash include: File not found errors, Invalid file permissions, and Division by zero errors.
  3. Logic Errors: These errors are caused by faulty logic within the script. While they may not cause an immediate crash, they can lead to unpredictable behaviour. This type of error is more difficult to detect.
  4. Input Errors: Input errors are caused by unexpected user inputs. Proper validation mechanisms should be implemented to handle diverse user inputs and prevent script failures.
  5. Environmental Errors: Environmental errors result from dependencies or configuration issues. These errors impact the script’s interaction with its environment. Scripts relying on external factors may encounter errors if these dependencies are not present or configured correctly.

7 Error Handling Techniques in Bash Script

In bash scripting, several error-handling methods improve the robustness of the scripts. Here are some important error handling methods given and discussed below:

1. Using Conditional “if-else” Statement to Handle Error

In bash scripting, if else statement is one of the most useful techniques that can be used to handle errors and control the flow of the script according to certain conditions. If you use this structure in your script, you will be able to create a script that is responsive and can be changed depending on the situation.

To understand the concept, let’s first sum two numeric values based on the given positional input. Here’s a simple Bash script that sums two numbers using positional parameters:

#!/bin/bash

# Sum the two numbers using positional parameters
sum=$(( $1 + $2 ))

# Print the result
echo "Sum of $1 and $2 is: $sum"
EXPLANATION

In this Bash script, two numbers are passed to the command-line as positional parameters using $1, $2. The sum of these two numbers is calculated in the variable ‘sum’. Then, the original numbers are passed back to the console with their sum value using the echo command.

Using Conditional “if-else” Statement to Handle ErrorIn the first scenario, the script “sum.sh” is executed with two numeric inputs: 3 and 4, and it returns a valid output. However, in the second scenario, three different numeric values are given but the code is designed to only take two positional arguments. This may result in a misleading return value. In the last scenario, one numeric and one string value are provided, but the code requires only a numeric value to perform the sum. Therefore, except for the first case, the return value may not be accurate and can mislead someone.

Now to handle those errors, you can incorporate an if-else statement in the existing code.

Below is a simple Bash script that uses if-else statement to handle errors efficiently:

#!/bin/bash

# Check if two arguments are provided
if [ $# -ne 2 ]; then
    echo "Error: Please provide exactly two numeric arguments."
    exit 1
fi

# Check if both arguments are numeric
if [[ "$1" =~ ^[0-9]+$ ]] && [[ "$2" =~ ^[0-9]+$ ]]; then
    # Perform the sum and print the result
    sum=$(( $1 + $2 ))
    echo "Sum of $1 and $2 is: $sum"
else
    echo "Error: Both arguments must be numeric."
fi 
EXPLANATION

This Bash script validates whether exactly two numeric arguments are provided. It checks the number of arguments using [ $# -ne 2 ] and prints an error message if the condition is true, followed by an exit with a non-zero status. Next, it verifies if both arguments are numeric using regular expressions with [[ "$1" =~ ^[0-9]+$ ]] && [[ "$2" =~ ^[0-9]+$ ]] . If this condition is met, it calculates the sum of the two numbers and prints the result. If either argument is not numeric, an error message is displayed.

Using Conditional “if-else” Statement to Handle Error-2As the image suggests, the updated bash script successfully handles the error for the last two cases.

Using Conditional “if-else” Statement and “AND” Operator to Handle Error

You can accomplish the same by only using if-else statement and the AND operator. Here is a reference code, you can follow:

#!/bin/bash

# Check if two arguments are provided and both are numeric
if [[ $# -eq 2 && "$1" =~ ^[0-9]+$ && "$2" =~ ^[0-9]+$ ]]; then
    # Perform the sum and print the result
    sum=$(( $1 + $2 ))
    echo "Sum of $1 and $2 is: $sum"
else
    echo "Error: Please provide exactly two numeric arguments."
fi
EXPLANATION

The Bash script begins by checking if it receives exactly two command-line arguments and if both are numeric. The condition [[ $# -eq 2 && "$1" =~ ^[0-9]+$ && "$2" =~ ^[0-9]+$ ]] verifies this requirement. If the condition is met, the script proceeds to perform the sum of the two numeric arguments using $(( $1 + $2 )). The result is then echoed to the terminal with a message indicating the sum of the provided numbers. If the condition is not satisfied, an error message is displayed, indicating that the user should provide exactly two numeric arguments.

Using Conditional “if-else” Statement and “AND” Operator to Handle ErrorAs you can see, upon execution the code returns the same output as it did in the previous code for all three cases.

2. Using PIPESTATUS to Handle the Error in Pipeline

In Bash, the PIPESTATUS array allows you to access the exit status of each command in a pipeline. It allows you to know which command has failed in your script based on the exit status. The exit status is a number that is returned to the operating system after the execution of the command or a script.

In the Unix-like operating system, including Linux, there is a convention where an exit status value of 0 indicates that the command executed successfully, and any value that is not zero indicates that the command encountered an error or some kind of failure.

To use PIPESTATUS to find the failed command in a pipeline, use the following code and handle the error:

#!/bin/bash

# Example commands in a pipeline
command1=" ls /home/miran"
command2="grep LinuxSimply.txt"

# Execute the pipeline and capture the exit status
${command1} | ${command2}
pipeline_status=("${PIPESTATUS[@]}")

# Check the exit status of each command
if [ "${pipeline_status[0]}" -ne 0 ]; then
  echo "Error: Command 1 failed with exit status ${pipeline_status[0]}"
fi

if [ "${pipeline_status[1]}" -ne 0 ]; then
  echo "Error: Command 2 failed with exit status ${pipeline_status[1]}"
else
  echo "Pipeline executed successfully!"
fi
EXPLANATION

This Bash script demonstrates the use of the PIPESTATUS array to capture the exit statuses of commands in a pipeline. Two example commands, ls /home/miran and grep LinuxSimply.txt, are combined in a pipeline. The script executes the pipeline and captures the exit statuses using ${PIPESTATUS[@]}. It then checks the exit status of each command separately, displaying an error message with the corresponding exit status if any command fails. If both commands succeed, it prints a success message indicating that the entire pipeline executed successfully.

Using PIPESTATUS to Handle the Error in PipelineWhile running the abovementioned bash code, the ls /home/miran exists but LinuxSimply.txt does not exist in the given directory. So the second command failed while executing the bash file. The exit status of the failing command2 is 1 in this case. Thus, the code returns “Error: Command 2 failed with exit status 1” in the command line.

3. Using the Exit Status Code to Handle Error

The exit status code plays a vital role in error handling in bash scripts. When a command executes, its output status is saved in the $? variable. A value of 0 indicates that the command executed successfully, while a non-zero value indicates that the command failed.

You can always use the exit status code to handle the error. Here is an example of how you can handle an error using the exit status code:

#!/bin/bash

# Example command that may fail
ls /home/miran/ | grep "LinuxSimply.txt" 2>/dev/null

# Check the exit status
if [ $? -ne 0 ]; then
  echo "Error: Command failed with exit status $?" >&2
  exit 1  # Exit the script with a non-zero status
fi

# Continue with the rest of the script for successful execution
echo "Command executed successfully."
EXPLANATION

The ls /home/miran/ | grep "LinuxSimply.txt" 2>/dev/null command in the script is an attempt to list the contents of the /home/miran/ directory using the ls command and then filter the results with grep command to find the file named “LinuxSimply.txt”. The 2>/dev/null at the end of the command redirects any potential error output (stderr) to /dev/null to suppress any error messages on the terminal.

Then, the script checks the previous command’s exit status using the $? variable. If the exit status is non-zero, indicating a failure, an error message is echoed to stderr with echo "Error: Command failed with exit status $?" >&2, and the script is terminated with exit 1, ensuring a non-zero exit status. If $? variable contains value 0, the code will return “Command executed successfully.” to the terminal.

Using the Exit Status Code to Handle ErrorSince the specified directory /home/miran/ exists but does not contain the file named LinuxSimply.txt, the command fails and ultimately returns a zero exit status code. As you can see from the image, the zero exit status code is displayed on the terminal with an error message stating that the command failed.

Note: As the ls /home/miran/ | grep "LinuxSimply.txt" 2>/dev/null command fails, you may wonder why the exit code is 0 instead of non-zero value. This is because $? always contains the last command line’s exit code. Though we are making a decision here based on ls /home/miran/ | grep "LinuxSimply.txt" 2>/dev/null, in echo "Error: Command failed with exit status $?" >&2 line the $? variable contains the exit code of the previous line if [ $? -ne 0 ]; then, which is a successful execution.

4. Using “set -e” to Stop the Execution

By using the set -e parameter in a bash script, you can terminate the script automatically if any of the commands in the script exits with non-zero status. This can improve the reliability of the script by stopping execution when it encounters an error, without having to explicitly check the exit status after every command.

Here is an example of handling error using set -e command:

#!/bin/bash

# Enable the 'set -e' option
set -e

echo "This line will be executed as there is no error yet."

# Example commands that may fail
ls /home/miran/ | grep "LinuxSimply.txt" 2>/dev/null

# The script will automatically exit if the above command fails
# and the following commands won't be executed.

# Continue with the rest of the script for successful execution
echo "This line won't be reached if there's an error."
EXPLANATION

The Bash script initiates by enabling the set -e option, instructing the script to exit immediately if any subsequent command returns a non-zero exit status. Following this, an echo statement confirms that the line will be executed as there has been no error up to this point.

Subsequently, the script attempts to execute a pipeline involving the ls command and grep to find “LinuxSimply.txt” in the /home/miran/ directory. The 2>/dev/null at the end of the command suppresses any potential error messages. Since set -e is in effect, if the pipeline fails (non-zero exit status), the script will terminate, and subsequent commands won’t be executed. Finally, there’s an echo statement indicating that the following line won’t be reached if there’s an error.

Using “set -e” to Stop the ExecutionSince there is no LinuxSimply.txt in the /home/miran/ directory. The given code returns a non-zero status in ls /home/miran/ | grep "LinuxSimply.txt" 2>/dev/null line. And there is no line print except “This line will be executed as there is no error yet.” because it was executed before encountering the error.

5. Using “trap” Command with ERR Argument

The trap command is another way to handle errors in a bash script. With the help of ERR signal built-in with the trap command,  you can define actions to be taken whenever any error occurs.

To handle errors, the Bash script below demonstrates the use of the trap command with the ERR signal:

#!/bin/bash

# Function to handle errors
handle_error() {
  echo "Error: Command failed with exit status $?" >&2
  exit 1
}

# Set up trap to call handle_error on ERR signal
trap 'handle_error' ERR

echo "This line will be executed as there is no error yet."

# Example commands that may fail
ls /home/miran/ | grep "LinuxSimply.txt" 2>/dev/null

# The script will automatically call handle_error if the above command fails
# and the following commands won't be executed.
echo "This line won't be reached if there's an error."
EXPLANATION

In this Bash script, the handle_error function is defined to handle errors. The trap command with ERR signal is used to automatically call handle_error when any next command fails. After the first echo command, the script tries to run a pipeline with the ls command and the grep command. The pipeline will suppress the error messages. The pipeline will fail, and handle_error will be called, stopping the execution of the next command.

Using “trap” Command with ERR ArgumentSince the LinuxSimply.txt file does not exist in the current directory, ls /home/miran/ | grep "LinuxSimply.txt" 2>/dev/null occurs an error and the code returns an error with exit status using the trap command and ERR argument.

6. Combining “set” and “trap” Commands for Error Handling

You can also combine both “set -e” and “trap” commands to handle errors. This action will enable you to stop the execution once the command finds an error and returns a customized error message.

Here’s an example of combining the set -e and trap commands in a Bash script:

#!/bin/bash

# Enable exit-on-error mode
set -e

# Function to be executed on error or script termination
cleanup_function() {
    echo "An error occurred. Cleaning up..."
    # Add cleanup actions here
}

# Trap the ERR signal and call the cleanup_function
trap 'cleanup_function' ERR

# Your script logic goes here
echo "Executing script..."

# Simulate a command failure
ls /nonexistent-directory

echo "Script completed successfully."
EXPLANATION

In this bash script, the set -e command is used to enable exit on error mode, so that if any other command returns nonzero status, the script will terminate. Then, the trap command is added to the script to catch the error ERR signal and run the cleanup_function if an error is encountered. The cleanup_function displays the error message and performs the cleanup actions. Finally, the deliberate command failure ls /nonexist-directory is incorporated to trigger cleanup_function if the command fails, which displays the error message. However, the script continues to execute until it reaches the concluding statement, “Script completed successfully”, showing a controlled script termination and cleanup process in reaction to an error.

Combining “set” and “trap” Commands for Error HandlingAs you can see from the image given above, the error occurs due to the /nonexistent-directory, thus the trap command with the help of ERR argument returns a customized error message to the terminal.

7. Allowing Script Execution Despite Errors

As you already know, a code’s set -e command allows you to terminate the execution if any error occurs. However, You can use the true command along with conditional execution (||) to allow script execution to continue despite errors. Here’s an example:

#!/bin/bash

set -e 

# Your script logic goes here
echo "Executing script..."

# Simulate a command failure but continue execution
ls /nonexistent-directory || true

# Another command that may fail
echo "Attempting another command..."
cat /nonexistent-file

echo "This line will not print if an error occurred and there is no true command in the error line."
EXPLANATION

Initially, the set -e command is used to enable the exit-on-error mode, causing the script to terminate if any command returns a non-zero status. Next, the ls /nonexistent-directory command is incorporated into the code to simulate command failure. However, the || true construct is appended to the command, ensuring that even if this command fails, the true command is executed, effectively ignoring the failure and allowing the script to continue.

The script then attempts another command (cat /nonexistent-file), which may fail. Since there is no || true construct after this command, the script would terminate if this command fails, and the subsequent echo statement would not be executed.

Allowing Script Execution Despite ErrorsAs shown in the image, when using the “ls” command, there is an error. Because the directory “/nonexistent-directory” does not exist. However, since the “true” command is used, the code continues to execute. But when the interpreter encounters the “cat /nonexistent-file” command, it stops executing the file because the file does not exist and cannot be read.

Conclusion

In conclusion, error handling is one of the most important aspects of Bash scripting. It ensures that scripts can handle unexpected events smoothly. Scriptwriters can use mechanisms like set -e, conditional execution, and trap command to balance the need for robust error detection with the need to maintain script continuity. This article has discussed some effective ways to handle errors in bash script. If you have further questions or confusion related to error handling in bash, feel free to comment below. Thank you!

People Also Ask

How does Bash handle errors?

There are several error-handling mechanisms in bash. For example, set -e allows you to exit on-error mode. If any command returns non-zero, the script will terminate. However, you can override this behavior with || true to continue executing the script despite errors.

The trap command lets you specify what to do when you receive certain signals. For example, if you receive ERR, you can define a cleanup function. Then, you can trap this ERR signal. This way, you can perform the necessary actions when you encounter ERR.

All of these features work together to provide you with the flexibility of error handling within bash scripts.

How do I trap errors in Bash?

In Bash, you can trap errors using the trap command, which allows you to define actions that should be taken when certain signals are received.

To trap errors, you specifically target the ERR signal. Here’s a concise example:

#!/bin/bash

# Function to be executed on error
cleanup_function() {
    echo "An error occurred. Cleaning up..."
    # Add cleanup actions here
}

# Trap the ERR signal and call the cleanup_function
trap 'cleanup_function' ERR

# Your script logic goes here
echo "Executing script..."

# Simulate a command failure
some_command_that_might_fail

# Rest of the script
echo "Script completed."

In this code, in place of some_command_that_might_fail, write your code here to effectively handle the error with the trap command with the ERR argument.

What is exit 1 in Bash?

“exit 1” is a command used in bash to exit a script or a shell session with an exit status of 1. In the context of Bash scripting, exit statuses are numerical values returned by executed commands. Where 0 typically indicates success and non-zero values indicate failure. On the other hand, an exit status of 1 is used to indicate that a command or script failed to execute correctly or encountered an error.

Here is an example of how to use exit 1 in a bash script:

#!/bin/bash
# Your script logic goes here

# Check for a specific condition
if [ ! -f "some_file.txt" ]; then
    echo "Error: File not found."
    exit 1
fi

# Continue script execution
echo "File found. Script completed successfully."

Here if the script doesn’t find the file “some _file.txt”, the script will print an error and exit with 1. This means that the calling environment will know that the script has encountered an error.

How do I stop Bash from errors?

To stop bash from error, use the set -e command at the beginning of your code:

# Enable exit-on-error mode
set -e

# Your script logic goes here

Thus the script will stop executing if encounters any error. However, it is generally recommended to handle errors rather than bypassing them entirely.  Because errors are essential for identifying and addressing issues in your scripts.

Related Articles


<< Go Back to Bash Error Handling and Debugging | Bash Scripting Tutorial

Rate this post
Mohammad Shah Miran

Hey, I'm Mohammad Shah Miran, previously worked as a VBA and Excel Content Developer at SOFTEKO, and for now working as a Linux Content Developer Executive in LinuxSimply Project. I completed my graduation from Bangladesh University of Engineering and Technology (BUET). As a part of my job, i communicate with Linux operating system, without letting the GUI to intervene and try to pass it to our audience.

Leave a Comment