Skip to content

Practice Exercise: Bash Script Debugging Techniques

Objectives

  • Learn how to debug Bash shell scripts effectively.
  • Explore various debugging techniques and tools available for Bash scripting.
  • Practice identifying and resolving common scripting errors.

Scenario

Debugging is a crucial skill for any Linux user or system administrator. In this exercise, you will learn and practice debugging techniques specific to Bash shell scripting. You will use debugging tools and strategies to identify and fix errors in Bash scripts.

Tasks

Task 1: Basic Script Debugging

  • Create a Bash script named basic_debugging.sh.
  • Write a simple script that contains intentional errors (e.g., syntax errors, undefined variables).
  • Attempt to run the script and document the error messages.
  • Use basic debugging techniques like adding echo statements to identify the issues.
  • Debug the script step by step until it runs without errors.
  • Document the debugging process and the changes made to the script.
  • Let's go back to the sales.csv
    Device,Quantity,Price
    Smartphone-A,10,599.99
    Tablet,12,399.99
    Smartphone-B,8,599.99
    Laptop,6,999.99
    Headphones-A,3,199.99
    Headphones-B,7,159.99
    
  • Let's make a script that calculates the total sales of each product
    [intern@intern-a1t-inf-lnx1 ~]$ cat basic_debugging.sh
    #!/bin/bash
    
    awk -F',' 'NR > 1 {sales[$3] += $2 * $1} END {for (product in sales) print "Product Name:", product, "Sales:", sales[product]}' sales.csv
    
    [intern@intern-a1t-inf-lnx1 ~]$ chmod +x basic_debugging.sh
    [intern@intern-a1t-inf-lnx1 ~]$ ./basic_debugging.sh
    Product Name: 199.99 Sales: 0
    Product Name: 399.99 Sales: 0
    Product Name: 599.99 Sales: 0
    Product Name: 999.99 Sales: 0
    Product Name: 159.99 Sales: 0
    
  • As you can see if you look at the csv file closely the sales shouldn't be zero
  • What you can do is echo the parameters to see if you have it in the correct order
    [intern@intern-a1t-inf-lnx1 ~]$ cat basic_debugging.sh
    #!/bin/bash
    
    awk -F',' 'NR > 1 {print $1" "$2" "$3" "} {sales[$3] += $2 * $1} END {for (product in sales) print "Product Name:", product, "Sales:", sales[product]}' sales.csv
    [intern@intern-a1t-inf-lnx1 ~]$ ./basic_debugging.sh
    Smartphone-A 10 599.99
    Tablet 12 399.99
    Smartphone-B 8 599.99
    Laptop 6 999.99
    Headphones-A 3 199.99
    Headphones-B 7 159.99
    Product Name: 199.99 Sales: 0
    Product Name: 399.99 Sales: 0
    Product Name: 599.99 Sales: 0
    Product Name: 999.99 Sales: 0
    Product Name: 159.99 Sales: 0
    Product Name: Price Sales: 0
    
  • You can see here that the $1 is the Product name, $2 is the quantity and $3 is the price
  • So we just need to swap the positions of our parameters
    [intern@intern-a1t-inf-lnx1 ~]$ cat basic_debugging.sh
    #!/bin/bash
    
    # {print $1" "$2" "$3" "}
    awk -F',' 'NR > 1 {sales[$1] += $2 * $3} END {for (product in sales) print "Product Name:", product, "Sales:", sales[product]}' sales.csv
    
    [intern@intern-a1t-inf-lnx1 ~]$ ./basic_debugging.sh
    Product Name: Tablet Sales: 4799.88
    Product Name: Smartphone-A Sales: 5999.9
    Product Name: Smartphone-B Sales: 4799.92
    Product Name: Headphones-A Sales: 599.97
    Product Name: Headphones-B Sales: 1119.93
    Product Name: Laptop Sales: 5999.94
    

Task 2: Debugging with set -x

  • Create a Bash script named debugging_setx.sh.
  • Write a script that performs a series of calculations or operations.
  • Use the set -x option at the beginning of the script to enable debugging mode.
  • Run the script and observe how it displays each executed command and its output.
  • Analyze the debugging output to identify any issues or unexpected behavior.
  • Make necessary adjustments to the script to resolve any problems.
    #!/bin/bash
    
    # Enable debugging mode
    set -x
    
    # This script performs a series of calculations or operations.
    
    # Example 1: Performing some calculations
    result=$((5 * 3))
    echo "Result of 5 * 3 is: $result"
    
    # Example 2: Concatenating strings
    name="John"
    greeting="Hello, $name!"
    echo $greeting
    
    # Example 3: Running a command
    ls /nonexistentfolder
    
    # Example 4: Using an undefined variable
    echo "The value of an undefined variable is: $undefined_var"
    
    # Disable debugging mode
    set +x
    
    # Continue with the rest of the script
    echo "Script execution completed."
    
[intern@intern-a1t-inf-lnx1 ~]$ chmod +x debugging_setx.sh
[intern@intern-a1t-inf-lnx1 ~]$ ./debugging_setx.sh
+ result=15
+ echo 'Result of 5 * 3 is: 15'
Result of 5 * 3 is: 15
+ name=John
+ greeting='Hello, John!'
+ echo Hello, 'John!'
Hello, John!
+ ls /nonexistentfolder
ls: /nonexistentfolder: No such file or directory
+ echo 'The value of an undefined variable is: '
The value of an undefined variable is:
+ set +x
Script execution completed.

Task 3: Debugging with set -e

  • Create a Bash script named debugging_sete.sh.
  • Write a script that simulates a process with multiple commands.
  • Use the set -e option at the beginning of the script to enable immediate exit on error.
  • Introduce intentional errors within the script (e.g., using a command that should fail).
  • Run the script and observe how it terminates immediately upon encountering an error.
  • Debug the script to handle errors gracefully without exiting.
    #!/bin/bash
    
    # Enable immediate exit on error
    set -e
    
    # This script simulates a process with multiple commands.
    
    # Example 1: Valid command
    echo "This is a valid command."
    
    # Example 2: Intentional error (command that should fail)
    ls /nonexistentfolder
    
    # Example 3: This command will not be executed due to the error above.
    echo "This command won't run because of the error."
    
    # Disable immediate exit on error for the remaining part of the script
    set +e
    
    # Continue with the rest of the script
    echo "Script execution completed."
    
    [intern@intern-a1t-inf-lnx1 ~]$ chmod +x debugging_sete.sh
    [intern@intern-a1t-inf-lnx1 ~]$ ./debugging_sete.sh
    This is a valid command.
    ls: /nonexistentfolder: No such file or directory
    

Task 4: Using trap for Error Handling

  • Create a Bash script named debugging_trap.sh.
  • Write a script that performs a specific task.
  • Implement a trap command to capture errors or signals (e.g., SIGINT) within the script.
  • Trigger an error condition (e.g., sending SIGINT with Ctrl+C) while the script is running.
  • Observe how the trap command handles the error or signal.
  • Modify the script to perform custom error handling and clean-up actions.
    #!/bin/bash
    
    
    trap "{ echo 'There was an error, aborting...'; exit 255; }" ERR SIGINT SIGTERM
    
    # This script performs a specific task.
    echo "Starting the task..."
    
    # Simulate an error condition (e.g., dividing by zero)
    ls /notexistingdirectory
    
    # This command won't be executed due to the error above.
    echo "This command won't run because of the error."
    
    # The script will terminate immediately upon encountering the error.
    
    # Any subsequent commands will not be executed.
    echo "This line will never be reached."
    
    # Continue with the rest of the script (if the custom error handler allows it).
    echo "Script execution completed."
    
    [intern@intern-a1t-inf-lnx1 ~]$   chmod +x debugging_trap.sh
    [intern@intern-a1t-inf-lnx1 ~]$ ./debugging_trap.sh
    Starting the task...
    ls: /notexistingdirectory: No such file or directory
    There was an error, aborting...
    

Task 5: Debugging with bash -n and bash -x

  • Create a Bash script named debugging_bash_n_x.sh.
  • Write a script that contains potential errors, such as unmatched quotes or missing fi statements in conditionals.
  • Use bash -n to perform a syntax check on the script without executing it.
  • Use bash -x to run the script in debug mode to identify issues.
  • Document the errors found and fix them in the script.
  • Run the script again to ensure it executes without errors.
    #!/bin/bash
    
    # This is a Bash script with potential errors for debugging practice
    
    # Uncomment the line below to introduce a syntax error (unmatched quotes)
    # echo "This line has a missing closing quote.
    
    # Uncomment the line below to introduce a missing 'fi' in a conditional statement
    # if [ 1 -eq 1
    # then
    #   echo "This line should not run."
    # fi
    
    # Uncomment the line below to introduce an undefined variable error
    # echo "The value of undefined_variable is: $undefined_variable"
    
    # Uncomment the line below to introduce a command that fails
    # This assumes you have a non-existent command; you can replace it with an actual command that fails
    # non_existent_command
    
    # Uncomment the line below to introduce a division by zero error
    # result=$((10 / 0))
    
    # Uncomment the line below to introduce a successful command
    # echo "This line will run successfully."
    
    # Uncomment the line below to introduce a successful conditional statement
    # if [ 1 -eq 1 ]
    # then
    #   echo "This line will run."
    # fi
    
    [intern@intern-a1t-inf-lnx1 ~]$ bash -x debugging_bash_n_x.sh
    [intern@intern-a1t-inf-lnx1 ~]$ bash -n debugging_bash_n_x.sh
    
  • Ran each bash -x and bash -n whenever you uncomment and fix errors in the script

Conclusion

In this exercise, you've practiced various debugging techniques for Bash shell scripting. Debugging is an essential skill for resolving scripting errors efficiently. Understanding how to use debugging tools and strategies will help you write more reliable Bash scripts.