How to Debug Scripts in Bash

How to Debug Scripts in Bash


When I was first starting out with some command line automation and development, I remember spending many hours trying to find the error in my code, and in the end, it could be something very simple, like a comma. You may have faced the same situation as well.

Knowing how to use proper debugging technique will help you resolve errors quickly. Unlike other languages, there is no debugging tool for bash where you can set breakpoints, step through code, etc. But you can enable some options in your scripts for debugging, which can help you, as follows:

Enable debugging flags from the shell when calling the script:

$ bash [debug flags] scriptname
Enable debugging options by passing debugging flags to the shebang line in the script.

#!/bin/bash [debug flags]
Enable debugging options using the script’s set command.

set -o nounset 
set -u
Enter fullscreen mode

Exit fullscreen mode

The command set is a shell builtin command that can be used to control bash parameters and alter its behavior in certain ways. It will be widely used within shell scripts, either for debugging or to enable strict bash mode. Normally, you won’t run configuration commands from the terminal to modify your shell’s behavior.



Debugging

Before we get into the debugging options, I must tell you that you can debug either the entire script or just a certain part of the code. You must use the set command to enable and disable the debugging options.

set -[flags] will enable debug mode.

set +[flags] will disable debug mode.

Take a look at the following code. set -x will enable xtrace mode for the script and set +x will disable xtrace mode. Everything between set -x and set +x will run in xtrace debugging mode.

#!/bin/bash

set -x
read -p "Pass Dir name : " D_OBJECT
read -p "Pass File name : " F_OBJECT
set +x

touch ${D_OBJECT}/${F_OBJECT}
Enter fullscreen mode

Exit fullscreen mode

When working with variables in bash, the disadvantage is that if we try to use an undefined variable, the script will not fail with some error message like “Undefined variable”. Instead, it will print an empty string.

In the code below, I am getting user input and storing it in the $OBJECT variable. I tried running the test operator (-f and -d) on the $OBJECT1 variable which is not defined.

#!/bin/bash

read -p "Object Name : " OBJECT
if [[ -f $OBJECT1 ]]
then
    echo "$OBJECT is a file"
elif [[ -d $OBJECT1 ]]
then
    echo "$OBJECT is a directory"
fi
Enter fullscreen mode

Exit fullscreen mode

When I run this code, it should have thrown me an error, but it didn’t and even the script exited with the return code zero. To override this behavior, use the flag -or,bash -u scriptname. generating an error message when an undefined variable is used, displaying an Unbound variable error message .

You can also set -u using the set command or pass it as an argument to the shebang.

set -u   
set -o nounset

#! /bin/bash -u
Enter fullscreen mode

Exit fullscreen mode



Xtrace – To the Rescue!

This is the mode I use when debugging bash scripts for logic errors. Xtrace mode will display the code line by line but with the parameters expanded. Now I can run the same script above, in xtrace mode and see exactly where the problem is occurring.

#!/bin/bash

read -p "Object Name : " OBJECT
if [[ -f $OBJECT1 ]]
then
    echo "$OBJECT is a file"
elif [[ -d $OBJECT1 ]]
then
    echo "$OBJECT is a directory"
fi
Enter fullscreen mode

Exit fullscreen mode

To debug this issue, I can run the script in xtrace mode passing the -x flag.bash -x scriptname. This tells me that there are empty strings assigned to the -f and -d conditional statements.

$ bash -x scriptname
+ read -p 'Object Name : ' OBJECT
Object Name: /test/
+ [[-f '']]
+ [[-d '']]
Enter fullscreen mode

Exit fullscreen mode

The + sign you see on stdout can be changed by putting the PS4 variable in the script. By default PS4 is set to (+), by throwing an echo $PS4 you will be able to verify it. To change it throw something like this:

$PS4=" >> " bash -x scriptname
Enter fullscreen mode

Exit fullscreen mode

changing the + sign to >> in the stdout of your script.

You can also set Xtrace mode using the set command or pass it as an argument to the shebang.

set -x set -o xtrace

#! /bin/bash -x
Enter fullscreen mode

Exit fullscreen mode

Don’t forget, that you can redirect debug logs to a file instead of printing them to the terminal. For example, to the code above add a few lines, after the shebang. assign a file descriptor 6 to the .log file and BASH_XTRACEFD=»6″ will redirect xtrace debug logs to file descriptor 6.

#!/bin/bash

exec 6> debug_output.log
BASH_XTRACEFD="6"
....
Enter fullscreen mode

Exit fullscreen mode

When I run this code instead of printing the output of xtrace to the terminal, it will be redirected to the output_debug.log file . Using cat , we will be able to read it inside the terminal.



Bash strict mode

To eliminate all the possible errors we have seen, you can add some options in each script.

  • -e Exit the script if any command returns a non-zero exit code.
  • -u Cause the script to fail if an undefined variable name is used.
  • pipefail If any command in the pipeline fails, the exit code will be considered for the entire
  • IFS Internal field separator, setting it to newline (n) and (t) will cause splitting to occur only on newline and tab.
set -e   
    set -u   
    set -o pipefail
Enter fullscreen mode

Exit fullscreen mode

EITHER

    set -euo pipefail   
    IFS=$'nt'
Enter fullscreen mode

Exit fullscreen mode



Using TRAP

Imagine a scenario where your script is triggered, but you want to cancel it with a CTRL+C. In that case, SIGINT will be sent to your script. Using TRAP, you can catch this signal and execute some commands or functions.

The code below has a function called cleanup that will be executed when SIGINT is passed to the script.

trap 'cleaning' TERM INT
function clean(){
     echo "Running cleanup, user used CTRL + C"
    <some logic>
}
Enter fullscreen mode

Exit fullscreen mode



Print the code using Verbose mode

In verbose mode, the code will be printed before the result is returned. If the program requires interactive input, then only that line followed by a block of code will be printed.

Following this paragraph is a simple program that gets an object from the user and checks if object is a file or directory using a conditional statement.

#!/bin/bash

read -p "Object Name : " OBJECT

if [[ -f $OBJECT ]]
then
    echo "$OBJECT is a file"
elif [[ -d $OBJECT ]]
then
    echo "$OBJECT is a directory"
fi

Enter fullscreen mode

Exit fullscreen mode

Once the above code is executed, it will first print the code and then wait for user input, after which the rest of the code will be printed followed by the output. $OBJECT is either a directory or a file, as the case may be. As in the previous cases, you can set verbose mode using set or in the shebang.set -v,set -o verboseeither#! /bin/bash -v



Syntax errors – noexec mode

Syntax errors are very common in programs. You may have missed a quote or failed to exit the loop, etc. You can use the flag-n(noexec mode) to validate the syntax before executing the program.

Yes, if you forgot to put a brace, a bracket, a quote or a comma, thanks to this flag, you will be able to know it by displaying syntax error messages. By default, when you run a script, bash will validate the syntax and throw these errors even without using the noexec mode. Likewise, as before, you can use set -n,set -o noexeceither#! /bin/bash -n



Conclusion

Well, good reader, I hope all these insights about debugging bash scripts are useful to you. The big difference with other programming languages ​​is that it doesn’t have debugging tools apart from some integrated options. Sometimes, these options will be more than enough to get the job done and can save you from a tight spot. Until another post!



Source link
lol

By stp2y

Leave a Reply

Your email address will not be published. Required fields are marked *

No widgets found. Go to Widget page and add the widget in Offcanvas Sidebar Widget Area.