Build efficient Bash scripts with templates
Bash scripting templates allow you to automate admin tasks efficiently. The guide provides a structured approach for creating scripts. This starting point simplifies creating future scripts, and we’ll wrap up with some basic testing to ensure it functions as expected.
In the previous article in this series, you created a very small, one-line Bash script and explored the reasons for creating shell scripts and why they are the most efficient option for the system administrator, rather than compiled programs.
This time, you’ll begin creating a Bash script template that can be used as a starting point for other Bash scripts. The template will ultimately contain a Help facility, a licensing statement, several simple functions, and some logic to deal with those options and others that might be needed for the scripts that will be based on this template.
Why create a template?
Like automation in general, the idea behind creating a template is to be the “lazy sysadmin.” A template contains the basic components that you want in all of your scripts. It saves time compared to adding those components to every new script and makes it easy to start a new script.
While it may seem easier to quickly create an executable file with command-line Bash statements, a well-written and well-commented Bash program with a Help feature and the ability to accept command-line options is more effective in the long term.
Requirements
You should always create a set of requirements for every project you do. This includes scripts, even if it’s a simple list with only two or three items on it. I’ve seen many projects fail due to missing or poorly written requirements. Don’t let this happen to you.
The requirements for this Bash template are pretty simple:
- Create a template that can be used as the starting point for future Bash programming projects.
- The template should follow standard Bash programming practices.
- It must include:
- A heading section that can be used to describe the function of the program and a changelog
- A licensing statement
- A section for functions
- A Help function
- A function to test whether the program user is root
- A method for evaluating command-line options
The basic structure
A basic Bash script has three sections. Bash has no way to delineate sections, but the boundaries between the sections are implicit.
- All scripts must begin with the shebang (#!), and this must be the first line in any Bash program.
- The functions section must begin after the shebang and before the body of the program. As part of my need to document everything, I place a comment before each function with a short description of what it is intended to do. I also include comments inside the functions to elaborate further. Short, simple programs may not need functions.
- The main part of the program comes after the function section. This can be a single Bash statement or thousands of lines of code. One of my programs has a little over 200 lines of code, not counting comments. That same program has more than 600 comment lines.
That’s all there is—just three sections in the structure of any Bash program.
Leading comments
I always add more than this for various reasons. First, I add a couple of sections of comments immediately after the shebang. These comment sections are optional, but I find them very helpful.
The first comment section is the program name and description and a change history. I learned this format while working at IBM, and it provides a method of documenting the long-term development of the program and any fixes applied to it. This is an important start in documenting your program.
The second comment section is a copyright and license statement. I use GPLv2, and this seems to be a standard statement for programs licensed under GPLv2. It’s fine if you use a different Open Source license, but I suggest adding an explicit statement to the code to eliminate any potential confusion.
The script template looks like this to start.
#!/bin/bash
#######################################################################
# scriptTemplate #
# #
# Use this template as the beginning of a new program. Place a short #
# description of the script here. #
# #
# Change History #
# 11/11/2019 David Both Original code. #
# This is a template for creating new Bash #
# shell scripts. Add new history entries as #
# needed. #
# #
#######################################################################
# #
# Copyright (C) 2007, 2023 David Both #
# LinuxGeek46@both.org #
# #
# This program is free software; you can redistribute it and/or #
# modify it under the terms of the GNU General Public License as #
# published by the Free Software Foundation; either version 2 of the #
# License, or (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
# General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA #
# 02111-1307 USA #
#######################################################################
#######################################################################
echo "hello world!"
Run the program to verify that it works as expected.
Add a Help function
Even fairly simple Bash programs should have some sort of Help facility, even if it’s fairly rudimentary. Infrequent use or complexity makes Bash scripts hard to remember. A built-in Help function can solve this.
It allows you to view those things without having to inspect the code itself. A good and complete Help facility is also a part of program documentation.
About functions
In Bash scripting, functions are reusable blocks of code that you can execute by name at the command line, similar to any other command. These functions are also sometimes called procedures or subroutines in other programming languages.
You call Bash functions by name, just like any other command, either in scripts or directly at the command line (CLI). When a function is called, its code executes, then control returns to the place where the function was called, and the program continues from there.
The syntax of a function is:
FunctionName(){program statements}
Explore this by creating a simple function at the CLI. (The function is stored in the shell environment for the shell instance in which it is created.) You’re going to create a function called hw, which stands for “hello world.” Enter the following code at the CLI and press Enter. Then enter hw as you would any other shell command:
$ hw(){ echo "Hi there kiddo"; }
$ hw
Hi there kiddo
Let’s move beyond the textbook “Hello world.” Use the declare tool to list your defined functions. When you call a function, it executes its code and then returns control to where it was called, whether that’s the command line, a script, or the next statement after the function call.:
$ declare -f | less
<snip>
hw ()
{
echo "Hi there kiddo"
}
<snip>
Remove that function because you don’t need it anymore.
Run the unset command:
$ unset -f hw ; hw
bash: hw: command not found
Creating the Help function
Open the hello program in an editor and add the Help function below to the hello program code after the copyright statement and just before the echo “Hello world!” statement. This Help function will display a short description of the program, a syntax diagram and short descriptions of the available options. Add a call to the Help function to test it and some comment lines that provide a visual demarcation between the functions and the main portion of the program:
#######################################################################
# Help #
#######################################################################
Help()
{
# Display Help
echo "Add description of the script functions here."
echo
echo "Syntax: scriptTemplate [-g|h|v|V]"
echo "options:"
echo "g Print the GPL license notification."
echo "h Print this Help."
echo "v Verbose mode."
echo "V Print software version and exit."
echo
}
#######################################################################
# Main program #
#######################################################################
Help
The options described in this Help function are typical for the programs I write, although none are in the code yet.
Run the program to test it:
$ ./hello
Add description of the script functions here.
Syntax: scriptTemplate [-g|h|v|V]
options:
g Print the GPL license notification.
h Print this Help.
v Verbose mode.
V Print software version and exit.
Hello world!
$
Currently, the Help message displays every time. We’ll add logic to show it only when the -h option is used at the command line.
Handling options
A Bash script’s ability to handle command-line options such as -h can add some powerful capabilities to direct the program and modify how it works. In the case of the -h option, you want the program to print the Help text to the terminal session and then quit without running the rest of the program. The ability to process options entered at the command line can be added to the Bash script using the while command (see Programming with Bash Part 3: Loops to learn more about while) in conjunction with the getops and case commands.
The getops command reads any options specified at the command line and creates a list of those options. In the code below, the while command loops through the list of options by setting the variable $options for each. The case statement is used to evaluate each option in turn and execute the statements in the corresponding stanza. The while statement will continue to evaluate the list of options until they have all been processed or it encounters an exit statement, which terminates the program.
Be sure to delete the Help function call just before the echo “Hello world!” statement so that the main body of the program now looks like this:
#######################################################################
# Main program #
#######################################################################
# Process the input options. Add options as needed. #
#######################################################################
# Get the options
while getopts ":h" option; do
case $option in
h) # display Help
Help
exit;;
esac
done
echo "Hello world!"
Notice the double semicolon at the end of the exit statement in the case option for -h. This is required for each option added to this case statement to delineate the end of each option.
Testing
Now for testing: Let’s try running the program with no options (to see if it prints “Hello world!”) and with various options to see how it responds.
$ ./hello
Hello world!
That works, so now test the logic that displays the Help text:
$ ./hello -h
Add description of the script functions here.
Syntax: scriptTemplate [-g|h|t|v|V]
options:
g Print the GPL license notification.
h Print this Help.
v Verbose mode.
V Print software version and exit.
That works as expected, so try some testing to see what happens when you enter some unexpected options:
$ ./hello -x
Hello world!
$ ./hello -q
Hello world!
$ ./hello -lkjsahdf
Add description of the script functions here.
Syntax: scriptTemplate [-g|h|t|v|V]
options:
g Print the GPL license notification.
h Print this Help.
v Verbose mode.
V Print software version and exit.
$
The program just ignores any options without specific code for them without generating any errors. But notice the last entry (with -lkjsahdf for options): because there is an h in the list of options, the program recognizes it and prints the Help text. This testing has shown that the program can’t handle incorrect input and terminate the program if any is detected.
To handle unexpected options, add a final case (\?) to the case statement. This will catch any option not explicitly defined earlier.
Try this:
while getopts ":h" option; do
case $option in
h) # display Help
Help
exit;;
\?) # incorrect option
echo "Error: Invalid option"
exit;;
esac
done
Test the program again using the same options as before and see how it works now.
Summary
This enhanced script now handles command-line options and provides a Help function.
Your Bash script now looks like this:
#!/usr/bin/bash
#######################################################################
# scriptTemplate #
# #
# Use this template as the beginning of a new program. Place a short #
# description of the script here. #
# #
# Change History #
# 11/11/2019 David Both Original code. #
# This is a template for creating new Bash #
# shell scripts. Add new history entries as #
# needed. #
# #
#######################################################################
# #
# Copyright (C) 2007, 2023 David Both #
# LinuxGeek46@both.org #
# #
# This program is free software; you can redistribute it and/or #
# modify it under the terms of the GNU General Public License as #
# published by the Free Software Foundation; either version 2 of the #
# License, or (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU #
# General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program; if not, write to the Free Software #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA #
# 02111-1307 USA #
#######################################################################
#######################################################################
#######################################################################
# Help #
#######################################################################
Help()
{
# Display Help
echo "Add description of the script functions here."
echo
echo "Syntax: scriptTemplate [-g|h|v|V]"
echo "options:"
echo "g Print the GPL license notification."
echo "h Print this Help."
echo "v Verbose mode."
echo "V Print software version and exit."
echo
}
#######################################################################
# Main program #
#######################################################################
# Process the input options. Add options as needed. #
#######################################################################
# Get the options
while getopts ":h" option; do
case $option in
h) # display Help
Help
exit;;
\?) # incorrect option
echo "Error: Invalid option"
exit;;
esac
done
echo "Hello world!"
Next up in the series, we’ll explore testing in more detail.
