Bash debugging

TL;DR Add set -ex on your second line to debug (But wait, there’s more)

The Basics

When you write a bash script at some point you are forced to solve a problem. First install shellcheck to see if the script is made correctly and there are no obvious error.

Things will still not always five you the correct outcome, even when there are no error. Here is an example where you would want to show the files and directories of /tmp with the sub directories. The wrong code here is:

#!/bin/bash

ShowDir ()
{
    ls -AlF "$DIR"
}

DIR=tmp
ShowDir

So we run it and what do we get?

user@linux ~: script.sh
ls: cannot access 'tmp': No such file or directory

So clearly something is something wrong. The answer is that it should be /tmp and not tmp. If this is a larger script, this can be hard to find as you have no idea what goes on. To see what goes on you add set -x as the second line on your script or set -ex. The -x will start showing things. The -e will stop when an error is seen

#!/bin/bash
set -x
ShowDir ()
{
    ls -AlF "$DiR"
}

DIR=tmp
ShowDIr

The output now is

+ DIR=tmp
+ ShowDir
+ ls -AlF tmp
ls: cannot access 'tmp': No such file or directory

So you now no only see the outcome, but also that it did ls -AlF tmp and that DIR was tmp not /tmp as it should have been. This will already help you a lot with debugging.

More details

When you have a longer scrip, make it set -ex instead, so it stops when there is an error. That way yuu can see the last few lines and not let the script run on and on for a LONG time. That will make it hard to read.

You can send the output to a file with script.sh > script.log to read later. But when you have a lot of functions, it can become a bit up and down. You will also want to know what line things happen and obviously you will want some color. (Well, perhaps not. I add it anyway). We change the script to

#!/bin/bash
DEBUG=YES

#### Start of debugging ####
if [ "$DEBUG" == "YES" ]
then
        txtbld=$(tput bold)       # Bold
        txtgrn=$(tput setaf 2)    # Green
        txtblu=$(tput setaf 4)    # Blue
        txtoff=$(tput sgr0)       # Text reset
        SPACES=$(printf "%$(tput cols)s")
        PS4='+${txtbld}\
${txtgrn}${SPACES:0:$((5-${#LINENO}))}$LINENO \
${txtblu}${FUNCNAME:-${SPACES:0:12}}${FUNCNAME:+${SPACES:0:$((12 - ${#FUNCNAME}))}}\
${txtoff}'
        set -ex
fi      
##### End of debugging #####

# Start of the script
ShowDir ()
{
        ls -AlF $DIR
}       

DIR=tmp
ShowDir

When you run it now, you see the colors. The first number you see is the line number. The second column is the function and the third the information.

+   23             DIR=tmp
+   24             ShowDir
+   20 ShowDir     ls -AlF tmp

Add this to every script you have and just change the DEBUG=YES to DEBUG=NO, or anything or comment it out and you have your standard script. Use it as a default for each new script.