Debugging

In the very old days of computer technology, the initial problems with computers were due to real insects. Due to this, fault finding was later called as finding a bug. Therefore, the process of finding and fixing the problems in computers was called debugging.

The process of debugging involves the following:

  • Finding out what has gone wrong
  • Fixing the problem

In the actual debugging process, you will need to do the following:

  • Understand the error message and find out what is the problem with the script.
  • Find the error location in the script.
  • Locate the line number from the error message. The following are a few error messages:
    • debug_sp: line 11: [7: command not found]
    • file: line 6: unexpected EOF while looking for matching `"'

    These messages inform the user about the line numbers of script which contain errors.

  • Correct the issue or problematic part of code. We may have to read the line as well as look backward from this line number for any possible reason for the error.

Debugging mode – disabling the shell (option -n)

In the Bash shell, the -n option is a shortcut for noexec (as in no execution). This option tells the shell to not run the commands. Instead, the shell just checks for syntax errors.

We can test the script as follows:

$ bash –n hello.sh

The –n option will tell the Bash shell to check the syntax in the Shell script; but not to execute the Shell script.

Another way to do this is as follows:

#!/bin/bash  -n
We have modified shebang line.

In this case, we can test the Shell script as follows:

$ chmod u+x hello.sh
$ ./hello.sh

This option is safe, since the shell commands are not executed. We can catch incomplete if, for, while, case, and similar programming constructs as well as many more syntactical errors.

Let's write debug_01.sh:

#!/bin/bash
echo -n "Commands in bin directory are : $var"

for var in $(ls )
do
        echo -n -e "$var   "
do
# no error if "done" is typed instead of "do"

Save the file, give the permission to execute, and run the script as follows:

$ chmod  u+x debug_01.sh
$ ./debug_01.sh

Output:

Commands in bin directory are : ./hello.sh: line 7: syntax error near unexpected token `do'
./hello.sh: line 7: `do'

$ bash –n debug_01.sh

Output:

hello.sh: line 7: syntax error near unexpected token `do'
hello.sh: line 7: `do'

Debugging mode – displaying commands (option -v)

The -v option tells the shell to run in a verbose mode. In practice, this means that the shell will echo each command prior to executing the command. This will be useful in locating the line of script that has created an error.

We can enable the script execution with the –v option as follows:

$ bash –v hello.sh

Another way is by modifying the shebang line as follows:

#!/bin/bash  -v

In this case, we can run the script with the –v option as follows:

$ chmod u+x hello.sh
$ ./hello.sh

Let's write the script debug_02.sh, shown as follows:

#!/bin/bash
echo "Hello $LOGNAME"
echo "Today is `date`
echo "Your present working directory is $PWD
echo Good-bye $LOGNAME

Save the file, give the permission to execute, and run the script as follows:

$ chmod u+x debug_02.sh
$ ./debug_02.sh

Output:

Hello student
Today is Fri May 1 00:18:52 IST 2015
Your present working directory is /home/student/work
Good-bye student

Let's enable the –v option for debugging, and run the script again as follows:

$ bash –v debug_02.sh

Output:

#!/bin/bash
echo "Hello $LOGNAME"
"Hello student"
echo "Today is `date`
date
"Today is Fri May 1 00:18:52 IST 2015
echo "Your present working directory is $PWD
"Your present working directory is /home/student/work
echo Good-bye $LOGNAME
Good-bye student

Debugging mode – the tracing execution (option -x)

The -x option, short for xtrace or execution trace, tells the shell to echo each command after performing the substitution steps. Thus, we will see the value of variables and commands.

We can trace the execution of the Shell script as follows:

$ bash –x hello.sh

Instead of the previous way, we can modify the shebang line as follows:

#!/bin/bash  -x

Let's test the earlier script debug_01.sh as follows:

$ bash –x hello.sh

Output:

$ bash –x debug_02.sh
+ echo Hello student
Hello student
+ date
+ echo The date is Fri May 1 00:18:52 IST 2015
The date is Fri May 1 00:18:52 IST 2015
+ echo Your home shell is /bin/bash
Your home shell is /bin/bash
+ echo Good-bye student
Good-bye student

Let's try the following programs with the –n –v –f and –x options. Here's a sample program—debug_03.sh:

#!/bin/bash
echo "Total number of parameters are = $#"
echo "Script name = $0"
echo "First Parameter is $1"
echo "Second Parameter is $2"
echo "All parameters are = $*"
echo "File names starting with f* in current folder are :"
ls f*

Save the file, give the permission to execute, and run the script as follows:

$ chmod u+x debug_03.sh
$ ./debug_03.sh One Two

Output:

"Total number of parameters are = 2"
"Script name = ./debug_03.sh"
"First Parameter is India"
"Second Parameter is Delhi"
"All parameters are = India Delhi"
"File names starting with debug_02.sh debug_03.sh in current folder are: "
debug_02.sh  debug_03.sh

Let's test the same script with the –n option, which will check for syntax errors:

$ bash –n debug_03.sh One Two

Let's test the same script with the –v option:

$ bash –v debug_03.sh One Two

Output:

#!/bin/bash
echo "Total number of parameters are = $#"
"Total number of parameters are = 2"
echo "Script name = $0"
"Script name = debug_03.sh"
echo "First Parameter is $1"
"First Parameter is India"
echo "Second Parameter is $2"
"Second Parameter is Delhi"
echo "All parameters are = $*"
"All parameters are = India Delhi"
echo "File names starting with d* in current folder are :"
"File names starting with debug_02.sh debug_03.sh in current folder are: "
ls d*
debug_02.sh  debug_03.sh

Let us test the same script with the –x option:

$ bash –x debug_03.sh One Two

Output:

+ echo $'342200234Total' number of parameters are = $'2342200235'
"Total number of parameters are = 2"
+ echo $'342200234Script' name = $'debug_03.sh342200235'
"Script name = debug_03.sh"
+ echo $'342200234First' Parameter is $'India342200235'
"First Parameter is India"
+ echo $'342200234Second' Parameter is $'Delhi342200235'
"Second Parameter is Delhi"
+ echo $'342200234All' parameters are = India $'Delhi342200235'
"All parameters are = India Delhi"
+ echo $'342200234File' names starting with debug_02.sh debug_03.sh in current folder are $':342200234'
"File names starting with debug_02.sh debug_03.sh in current folder are: "
+ ls debug_02.sh debug_03.sh
debug_02.sh  debug_03.sh

Let's test one more program, which will give a syntax error during the –n and –x options debugging. Write the Shell script debug_04.sh as follows:

#!/bin/bash
echo "Commands in bin directory are : $var"

for var in $(ls )
do
        echo -n -e "$var   "
do

Save the file, give the permission to execute, and run the script as follows:

$ chmod u+x debug_04.sh
$ bash –n debug_04.sh

Output:

debug_04.sh: line 7: syntax error near unexpected token `do'
debug_04.sh: line 7: `do'

The preceding program has a syntax error on line number 7. The word do has an error. We need to change word "do" to "done".

Summarizing the debugging options for the Bash shell

The following is a summary of various debugging options used for debugging, such as -x, -v, and -n with their details:

$ bash –n script_name  // interpretation without execution
$ bash –v script_name  // Display commands in script
$ bash –x script_name  // Trace the execution of script

$ bash –xv script_name    // Enable options x and v for debugging
$ bash  +xv script_name    //Disable options x and v for debugging

Using the set command

Most of the time, we invoke the debugging mode from the first line of script. This debugging mode will remain active until the last line of code. But many times, we may need to enable debugging for a particular section of script. By using the set command, we can enable and disable debugging at any point in our Shell script:

set -x
section of script
set +x

Consider the following script:

#!/bin/bash

str1="USA"
str2="Canada";

[ $str1 = $str2 ]
echo $?

Set –x

[ $str1 != $str2 ]
echo $?

[ -z $str1 ]
echo $?

Set +x

[ -n $str2 ]
echo $?

Exit 0

In this case, the debugging will be enabled after the set -x and will be disabled immediately after the set +x.

Summary of debugging options for set command

The following table summarises the various options for the set command:

Short notation

Result

set -f

Disables globbing. In this case, the file name expansions using wildcards or metacharacters will be disabled.

set -v

This will print the Shell script lines as they are read by the shell.

set -x

This option will display each line after the variable substitution and command expansion, but before execution by the shell. This option is often called shell tracing.

set -n

This reads all commands and checks the syntax, but does not execute them.

The vi editor setting for debugging

For general debugging, we can use the vi editor along with certain options.

During debugging, many times we search for a pattern throughout the complete document. It is preferable to highlight the searched item. We will enable search pattern highlighting by using the following command in the vi editor when the document is opened:

:set hlsearch     :set ic  vi –b filename

We can even modify the vi editor configuration file—.exrc or .vimrc so that we need not give the previous command again and again.

Good practices for Shell scripts

If we follow certain good practices, then we will face errors. Even if errors are found, these will be easier to debug:

  1. Clear and tidy the script. Try to properly indent the programming constructs, such as if, for, while, and other similar loops:
    if [ $rate -lt 3 ]
    then
      echo "Sales tax rate is too small."
    fi
    
  2. Do not put multiple commands on the same line by using ;.
  3. Use descriptive variable names, such as salary, instead of sa. In very complex Shell scripts, non-descriptive variable names will make debugging very difficult.
  4. Store the file and directory names in variables instead of typing them again and again. If any change is required in the directory path, then making the change in the variable at one place will be sufficient:
    WORKING_DIR=$HOME/work
    if [ -e $WORKING_DIR]
    then
      # Do something....
    fi
    
  5. Use comments for an easier understating of script. This will make debugging easier to others. If it contains tricky or complex commands, then even after few months, we will need comments to understand our own script. A cute little trick today may become a challenge tomorrow.
  6. Print informative error messages. Write simpler scripts. Use simpler if, case, for, and or functions. It is practically observed that if scripts are simpler, then these scripts are easy to maintain over a long period of time, such as few years.
  7. Test the script again and again with various test scenarios and test cases. Check for all the possibilities of human error, such as bad input, insufficient arguments, nonexistent files, and similar possibilities.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset