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 |
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 and functions.
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 GetAnswer () # Mixed case works well for a function. 24 { 25 prompt=$1 26 echo -n $prompt 27 read answer 28 return $answer 29 } 30 31 GetAnswer "What is your favorite number? " 32 favorite_number=$? 33 echo $favorite_number 34 35 36 _uservariable=23 # Permissable, but not recommended. 37 # It's better for user-defined variables not to start with an underscore. 38 # 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 |
Break complex scripts into simpler modules. Use functions where appropriate. See Example 35-4.
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). |
... reading the UNIX source code to the Bourne shell (/bin/sh). I was shocked at how much simple algorithms could be made cryptic, and therefore useless, by a poor choice of code style. I asked myself, "Could someone be proud of this code?" | |
Landon Noll |
[1] | In this context, " magic numbers" have an entirely different meaning than the magic numbers used to designate file types. |