Shell Script Style Guide Banners Banner Example Detailed Banner Notes Lesser Banners Example of Function or Procedure Banners Example of Logical Block Banners Example of Function Definition with Logical Blocks Symbols Symbol Form Class Form Layout Layout Rules Layout Example

Design Considerations

One of the key design considerations for any piece of code is the house style to be used within your company or department. It will only take a short while to list out the rules you want others to follow but this will bring real benefits when someone new has to edit one of your files. There is nothing worse than changing someone else's code when you are not sure where objects are derived from or what variable names have been used already, or what they mean. If you use meaningful variable names, then the chances are, they'll be easier to spot in the code. Structure your code so that each section follows in a logical order, making the code easier to read. Sprinkle the code with comments, especially in the difficult to follow areas.

This next section is actually a copy of a Style Guide I created for my development team to follow. It follows all the rules you have been unwittingly exposed to whilst reading this book and a few more besides. You might want to use this as a basis for your own style guide, then again you may not. The choice is yours. But do give it a read first - Please!

Shell Script Style Guide:

This document is a Style Guide for writing and revising UNIX Shell Scripts. Following this style guide will ease the burden of future maintenance and greatly improve the readability of any conforming code segments. Users new to Shell Scripting should read this guide first and observe the layout rules when generating new code to preserve the house style and guarantee ease of future maintenance. The guide is broken down into three main areas:

  1. Banners
  2. Symbols
  3. Layout

Banners:

Script Banners are used to carry information about the whole script in a readable format. The rules used here create banners that are readable by script users and embedded code functions. Following this style is therefore essential for continued operation of some areas of code. The style and format of the UNIX Script Banners used here are composed of 4 main parts:

  1. Shell Language Indicator
  2. Title Line
  3. Description and Support
  4. History

Shown below is an example banner from a current UNIX Bourne shell script followed by a detailed breakdown of its component parts.

Banner Example


#!/bin/sh
########################################################
# resource (c) RHReepe 1996 February 26 Version 1.0    #
########################################################	
# Description: Allows resource maintenance for databases
# Syntax: resource(menu)                (Alias resource)
# Extern: s_banner s_answer s_menu_list s_menu_pick
########################################################
# Notes: The startup menu requests the user to choose
# between Resource Usage Report or Resource Delete options.
# A second menu displays a selection list of Resource Types
# to choose from. A third menu then displays a dynamic
# list of user entered files from the LIST subdirectory.
# The files contain lists of resource id's to process
# which are appropriate for the type selected in menu 2.
# Usage reports are generated for each production database
# in turn. Delete requests are processed against master
# databases at each site only, with an update to all
# production databases COST_MODEL_USAGE flag. Deletes
# will be propagated to production overnight by the 
# normal download mechanism from the masters.
#######################################################
# 19960226 RHR Genesis

Detailed Banner Notes:

  1. All the lines in this banner are comments, except:
  2. Line 1 is not a comment, it is a shell indicator (See - Definitions).
  3. Line 2 is the banner start marker.
  4. Line 3 is the header and contains 10 fields as follows:

# Comment Indicator
word Name of Script [must not include spaces - use the underscore]
Copyright Flag [used by s_version() function]
Authors name Must use one field
1996 Year of creation
February Month of creation
26 Day of creation
Version Key word [used by s_version() function]
Version Number Important to be field 9 - [Function s_version() expects it]
# End of Comment marker

  1. Line 4 is a banner divider line.
  2. Line 5 is a short description. Note the use of an Alias at the end of the line, which indicates that the script can be executed from any directory as the Alias will always point to the correct script at execution time. Also, the script name is followed by the word menu in parentheses which indicates that a menu will start up when the script runs [the script help expects it].
  3. Line 6 is a syntax description. Alternatives should be shown in brackets. Any optional arguments should be enclosed within square brackets [the script how expects it].
  4. Line 7 is a list of the external shell functions called by this script [useful when updating].
  5. Line 8 is a banner divider line.
  6. Line 9 is the start of an [Optional] Notes section which details operational processes for complex scripts. This can be as long or as short as required but please do not dump pages of detail here. If it is a complex procedure, break it down into smaller sections and put a note in each section.
  7. Line 22 is the banner end marker.
  8. Line 23 is the History start line. Comprised of Date in JIS format, Authors Initials, and Comment for each change of the script (Genesis indicates The Beginning of history for the script). Any comments should indicate what was there before the current change, what is there now is obvious for all to see.

Lesser Banners:

For function, procedure, or logical unit banners, much less detail is required. It is obvious from the main banner that the same overall condition apply for the whole script. So in these local banners, just the name and a short one-line description are required in the banner header. Notice how the actual function defintion name is used as part of the title in the banner. Also the heavy handed hashes (####) are replaced by the much lighter equals (====) for the banner markers, above and below the title line. There is an optional set of lines that can follow this local banner to describe the passed arguments if any. See below for details.

Example of Function or Procedure Banners:


#========================================	# Banner Marker
function_name()	# (c) Author: Does this...	# Name,Auth & Description
#=======================================	# Banner Marker
# Arg_1 = filename			# Argument 1 (Mandatory)
# Arg_2 = [number]			# Argument 2 (Optional)

Example of Logical_Block Banners:


#========================================
# Doing this to that...
#=======================================

As an option, for logical block banners, the equals (====) can be substituted by minus (----), to lighten the appearance even more. As shown in the following function definition:

Example of Function Definition with Logical Blocks:


#=========================================================
i_master_db_list() # (c) Author: Return List of Databases
#=========================================================
# Arg_1 = [host_name:THISHOST]
{	
    #-------------------------------
    # Get list of databases on host
    #-------------------------------
    for sid in s_sid_list ${1:-$THISHOST}
    do
	db_type=`echo $sid | cut -c6`
	#-------------------------------
	# If correct type - add to list
	#-------------------------------
	if [ "$db_type" = "m" ]
	then
	    master_db_list="$master_db_list $db_type"
	fi
    done
    echo "$master_db_list"
}

Symbols:

The format for code symbols is also important as an aid to readability and comprehension when modifying or creating scripts. Here are some general but useful guidelines laid down to help both layout and understanding of the code.

Symbol Form:

Symbol Illustration Description Style
In Stream Comments # Code Fragment # A comment (InitCaps - starts with #)
UNIX Keywords grep -i fred | wc -l # UNIX Commands (lowercase)
Writing Shell Variables variable="hello world" # Setting a Variable (lowercase)
Reading Shell Variables echo "$variable" # Retrieving Variable (lowercase)
Environment Variable echo "$THISHOST" # Retrieving Variable (UPPERCASE)
Internal Function i_sub_doit # Function Name (lowercase starts with i_)
External Function s_sub_doit # Function Name (lowercase starts with s_)

The use of symbol prefixes to identify class or some other connection between symbols is allowed as long as it is made plain by corresponding comments. So several variables starting with "r_" could be associated with some "remote" connection as shown at the start of the following code segment:

Class Form:


#=============================================
# Get Remote Database List from Remote Server
#=============================================
r_database_list=`s_sid_list $r_host`

Layout:

The layout of code within a script has a great impact on readability. In general the flow of the program should be immediately obvious from the general layout. To this end, indenting of code within predicates and loop constructs shall be observed. Generally, indenting should carried out by tab-stops, but for heavily nested code this will be relaxed in favour of 3 spaces per nesting level to stop the code leaving the page. The following rules show the most common layout placements.

Layout Rules:

  1. Use Blank Lines between logical programming blocks, function definitions, and any other programming construct which defines a related object, or complex command group.
  2. Use Tabs to indent code when inside loops, functions, or predicates.
  3. Use 3 Spaces to indent code if nesting level becomes too deep.
  4. Use in-stream comments to explain complex structures.
  5. Keep in-stream comments justified to a column - at least on a per block basis.
  6. Don't do it twice, use an internal function.
  7. If you use it again in another script, create an external function in one of the files called from $ORACLE_BASE/.profile_functions.
  8. Use variable names that mean something (up to 31 characters recognized).
  9. Echo all valid results to a logfile for cron scripts.
  10. Echo invalid results to screen (Cron will mail them back during a failure).
  11. Use -xv on line 1 (shell indicator) for debugging.
  12. Create all temporary files in /tmp directory.
  13. Use filename suffixes to indicate probable content (.log, .lst, .dat, .mnu, sql, etc.).
  14. Pre-delete temp files, but don't delete after use when debugging - they are handy for inspecting the outcome.
  15. Look though the list of available functions and subroutines, it may already be there.
  16. Use the .profile files to get a good selection of existing predefined variables. They may save you some time.

The following example shows most of the rules in action within a dummy script layout. For a much broader example of the house style, users are requested to inspect the current UNIX shell scripts in the $ORACLE_BASE/scripts directory or the $ORACLE_BASE/cron directory.

Layout Example:


. $HOME/.profile			# Read default environment
tmp0=`s_tmp 0`			# Create temporary file name
tmp1=`s_tmp 1`			# Create temporary file name
#===================================
# Create SQL statement in Temp file 
#===================================
cat >> $tmp0 <<-EOF			# Fill tempfile with data to EOF
    SELECT name FROM v\$database;	# First line of data
    EXIT				# SQL EXIT statement
EOF				# EOF flag marker 
#========================
# Set up Account Strings
#========================
s_set_account_name "$system_coded" $0 $$	# Pass Coded UserID 
. $account_string$$				# Retrieve Login String
#========================================
# Loop through Databases and Process SQL 
#========================================
db_sid_list=`s_sid_list $THISHOST`	# Create DB list for this host
for sid in $db_sid_list		# Loop to process each DB in list
do				# Start of DO LOOP
    sql_command="sqlplus -s $account@t:$THOSHOST:$sid" # Create Login string
    $sql_command @$tmp0 >> $tmp1	# Run SQL and log output
done				# End of DO LOOP
Home Next Preface Introduction Basic Shells Shell Syntax Built-In Commands Command Substitution Startup & Environment Pipes, Lists & Redirection Input & Output Using Files Design Considerations Functions Debugging Putting It All Together Appendix Code Examples Page 211 This page was brought to you by rhreepe@injunea.demon.co.uk