Chapter 4. Modularizing and Debugging

In the real world, when you write code, you either maintain it forever or someone takes ownership of it later and makes changes into it. It is very important that you write a good quality shell script so that it's easier to maintain it further. It is also important that the shell script is bug-free in order to get the work done as expected. Scripts running on production systems are very critical because any error or wrong behavior of the script may cause minor or major damage. To solve such critical issues, it is important to get it fixed as soon as possible.

In this chapter, we will see how we can write modular and reusable code so that maintaining and updating our shell script application can be done quickly and without any hassle. We will also see how easily and quickly bugs in shell scripts can be solved using different debugging techniques. We will see how we can provide our users different choices for different tasks by providing support for command line options in a script. The knowledge of how to provide command line completion in a script will even increase the ease of using the script.

This chapter will cover the following topics in detail:

  • Modularizing your scripts
  • Passing command line parameters to script
  • Debugging your scripts
  • Command completion

Modularizing your scripts

While writing a shell script, there is one stage when we feel that a shell script file has become too big to read and manage. To avoid such a scenario in our shell script, it is very important to keep the script modular.

In order to keep the script modular and maintainable, you can do the following:

  • Create functions instead of writing the same code again and again
  • Write a common set of functions and variables in a separate script and then source to use it

We have already seen how to define and use a function in Chapter 3, Effective Script Writing. Here, we will see how to divide a bigger script into smaller shell script modules and then use them by sourcing. In other words, we can say creating libraries in bash.

Source to a script file

Source is a shell built in command that reads and executes a script file in the current shell environment. If a script calls a source on another script file, all functions and variables available in that file will be loaded for use in calling script.

Syntax

The syntax of using the source is as follows:

source <script filename> [arguments]

OR:

. <script filename> [arguments]

The script filename can be with or without a path name. If the absolute or relative path is provided, it will look only into that path. Otherwise, a filename will be searched in the directories specified in the PATH variable.

The arguments are treated as positional parameters to the script filename.

The exit status of the source command will be the exit code of the last command executed in the script filename. If the script filename doesn't exist or there is no permission, then the exit status will be 1.

Creating a shell script library

A library provides a collection of features that can be reused by another application without rewriting from scratch. We can create a library in shell by putting our functions and variables to be reused in a shell script file.

The following shell_library.sh script is an example of a shell library:

#!/bin/bash
# Filename: shell_library.sh
# Description: Demonstrating creation of library in shell

# Declare global variables
declare is_regular_file
declare is_directory_file

# Function to check file type
function file_type()
{
  is_regular_file=0
  is_directory_file=0
  if [ -f $1 ]
  then
    is_regular_file=1
  elif [ -d $1 ]
  then
    is_directory_file=1
  fi
}

# Printing regular file detail
function print_file_details()
{
   echo "Filename - $1"
   echo "Line count - `cat $1 | wc -l`"
   echo "Size - `du -h $1 | cut -f1`"
   echo "Owner - `ls -l $1 | tr -s ' '|cut -d ' ' -f3`"
   echo "Last modified date - `ls -l $1 | tr -s ' '|cut -d ' ' -f6,7`"
}

# Printing directory details
function print_directory_details()
{
   echo "Directory Name - $1"
   echo "File Count in directory - `ls $1|wc -l`"
   echo "Owner - `ls -ld $1 | tr -s ' '|cut -d ' ' -f3`"
   echo "Last modified date - `ls -ld $1 | tr -s ' '|cut -d ' ' -f6,7`"
}

The preceding shell_library.sh shell script contains the is_regular_file and is_directory_file global variables that can be used to know whether a given file is a regular file or directory after invoking the file_type()function. Furthermore, depending upon the type of the file, useful detailed information can be printed.

Loading a shell script library

Creating shell libraries are of no use unless it is used in another shell script. We can either use a shell script library directly in shell or within another script file. To load a shell script library, we will use the source command or. (period character) followed by shell script library.

Calling a shell library in bash

To use the shell_library.sh script file in shell, we can do the following:

$ source  shell_library.sh

OR:

$ . shell_library.sh

Calling any of them will make functions and variables available for use in the current shell:

$ file_type /usr/bin
$ echo $is_directory_file
1
$ echo $is_regular_file
0
$ if [ $is_directory_file -eq 1 ]; then print_directory_details /usr/bin; fi
Directory Name - /usr/bin
File Count in directory - 2336
Owner - root
Last modified date - Jul 12

When the file_type /usr/bin command is executed, the file_type()function with the /usr/bin parameter will be called. As a result, the global variable is_directory_file or is_regular_file will get set to 1 (true), depending upon the type of the /usr/bin path. Using the shell if condition, we test whether the is_directory_file variable is set to 1 or not. If set to 1, then call the print_directory_details() function with /usr/bin as a parameter to print its details.

Calling shell library in another shell script

The following example explains the usage of the shell library in a shell script file:

#!/bin/bash
# Filename: shell_library_usage.sh
# Description: Demonstrating shell library usage in shell script

# Print details of all files/directories in a directory
echo "Enter path of directory"
read dir

# Loading shell_library.sh module
. $PWD/shell_library.sh

# Check if entered pathname is a directory
# If directory, then print files/directories details inside it
file_type $dir
if [ $is_directory_file -eq 1 ]
then
   pushd $dir > /dev/null       # Save current directory and cd to $dir
   for file in `ls`
   do
     file_type $file
     if [ $is_directory_file -eq 1 ]
     then
       print_directory_details $file
       echo
     elif [ $is_regular_file -eq 1 ]
     then
       print_file_details $file
       echo
     fi
   done
fi

The output after running the shell_library_usage.sh script is as follows:

$ sh  shell_library_usage.sh	# Few outputs from /usr directory
Enter path of directory
/usr
Directory Name - bin
File Count in directory - 2336
Owner - root
Last modified date - Jul 12

Directory Name - games
File Count in directory - 0
Owner - root
Last modified date - Aug 16

Directory Name - include
File Count in directory - 172
Owner - root
Last modified date - Jul 12

Directory Name - lib
File Count in directory - 603
Owner - root
Last modified date - Jul 12

Directory Name - lib64
File Count in directory - 3380
Owner - root
Last modified date - Jul 12

Directory Name - libexec
File Count in directory - 170
Owner - root
Last modified date - Jul 7

Note

To load a shell script library, use source or . followed by script_filename.

Both source and .(period character) execute a script in the current shell. ./script is not the same as . script because ./script executes the script in a subshell, while . script executes in a shell from where it was invoked.

..................Content has been hidden....................

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