3.31. Scripting With Style

Get into the habit of writing shell scripts in a structured and systematic manner. Even "on-the-fly" and "written on the back of an envelope" scripts will benefit if you take a few minutes to plan and organize your thoughts before sitting down and coding.

Herewith are a few stylistic guidelines. This is not intended as an Official Shell Scripting Stylesheet.

  • Comment your code. This makes it easier for others to understand (and appreciate), and easier for you to maintain.

       1 PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}"
       2 # It made perfect sense when you wrote it last year, but now it's a complete mystery.
       3 # (From Antek Sawicki's "pw.sh" script.)

    Add descriptive headers to your scripts and functions.

       1 #!/bin/bash
       2 
       3 #************************************************#
       4 #                   xyz.sh
       5 #           written by Bozo Bozeman            
       6 #                July 05, 2001
       7 
       8 #           Clean up project files.
       9 #************************************************#
      10 
      11 BADDIR=65                       # No such directory.
      12 projectdir=/home/bozo/projects  # Directory to clean up.
      13 
      14 #-------------------------------------------------------#
      15 # cleanup_pfiles ()
      16 # Removes all files in designated directory.
      17 # Parameter: $target_directory
      18 # Returns: 0 on success, $BADDIR if something went wrong.
      19 #-------------------------------------------------------#
      20 cleanup_pfiles ()
      21 {
      22   if [ ! -d "$1" ]  # Test if target directory exists.
      23   then
      24     echo "$1 is not a directory."
      25     return $BADDIR
      26   fi
      27 
      28   rm -f "$1"/*
      29   return 0   # Success.
      30 }  
      31 
      32 cleanup_pfiles $projectdir
      33 
      34 exit 0
    Be sure to put the #!/bin/bash at the beginning of the first line of the script, preceding any comment headers.

  • Avoid using "magic numbers", [1] that is, "hard-wired" literal constants. Use meaningful variable names instead. This makes the script easier to understand and permits making changes and updates without breaking the application.

       1 if [ -f /var/log/messages ]
       2 then
       3   ...
       4 fi
       5 # A year later, you decide to change the script to check /var/log/syslog.
       6 # It is now necessary to manually change the script, instance by instance,
       7 # and hope nothing breaks.
       8 
       9 # A better way:
      10 LOGFILE=/var/log/messages  # Only line that needs to be changed.
      11 if [ -f $LOGFILE ]
      12 then
      13   ...
      14 fi

  • Choose descriptive names for variables.

       1 fl=`ls -al $dirname`              # Cryptic.
       2 file_listing=`ls -al $dirname`    # Better.
       3 
       4 
       5 MAXVAL=10   # All caps used for a script constant.
       6 while [ "$index" -le "$MAXVAL" ]
       7 ...
       8 
       9 
      10 E_NOTFOUND=75                   # Uppercase for an errorcode,
      11                                 # and name begins with "E_".
      12 if [ ! -e "$filename" ]
      13 then
      14   echo "File $filename not found."
      15   exit $E_NOTFOUND
      16 fi  
      17 
      18 
      19 MAIL_DIRECTORY=/var/spool/mail/bozo  # Uppercase for an environmental variable.
      20 export MAIL_DIRECTORY
      21 
      22 
      23 _uservariable=23                # Permissable, but not recommended.
      24 # It's better for user-defined variables not to start with an underscore.
      25 # Leave that for system variables.

  • Use exit codes in a systematic and meaningful way.

       1 E_WRONG_ARGS=65
       2 ...
       3 ...
       4 exit $E_WRONG_ARGS
    See also Appendix C.

  • Break complex scripts into simpler modules. Use functions where appropriate. See Example 3-168.

  • Don't use a complex construct where a simpler one will do.

       1 COMMAND
       2 if [ $? -eq 0 ]
       3 ...
       4 # Redundant and non-intuitive.
       5 
       6 if COMMAND
       7 ...
       8 # More concise (if perhaps not quite as legible).

Notes

[1]

In this context, " magic numbers" have an entirely different meaning than the magic numbers used to designate file types.