Comment your code. This makes it easier for others to understand (and appreciate), and easier for you to maintain.
PASS="$PASS${MATRIX:$(($RANDOM%${#MATRIX})):1}" # It made perfect sense when you wrote it last year, #+ but now it's a complete mystery. # (From Antek Sawicki's "pw.sh" script.) |
Add descriptive headers to your scripts and functions.
#!/bin/bash #************************************************# # xyz.sh # # written by Bozo Bozeman # # July 05, 2001 # # # # Clean up project files. # #************************************************# E_BADDIR=85 # No such directory. projectdir=/home/bozo/projects # Directory to clean up. # --------------------------------------------------------- # # cleanup_pfiles () # # Removes all files in designated directory. # # Parameter: $target_directory # # Returns: 0 on success, $E_BADDIR if something went wrong. # # --------------------------------------------------------- # cleanup_pfiles () { if [ ! -d "$1" ] # Test if target directory exists. then echo "$1 is not a directory." return $E_BADDIR fi rm -f "$1"/* return 0 # Success. } cleanup_pfiles $projectdir exit $? |
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.
if [ -f /var/log/messages ] then ... fi # A year later, you decide to change the script to check /var/log/syslog. # It is now necessary to manually change the script, instance by instance, #+ and hope nothing breaks. # A better way: LOGFILE=/var/log/messages # Only line that needs to be changed. if [ -f "$LOGFILE" ] then ... fi |
Choose descriptive names for variables and functions.
fl=`ls -al $dirname` # Cryptic. file_listing=`ls -al $dirname` # Better. MAXVAL=10 # All caps used for a script constant. while [ "$index" -le "$MAXVAL" ] ... E_NOTFOUND=95 # Uppercase for an errorcode, #+ and name prefixed with E_. if [ ! -e "$filename" ] then echo "File $filename not found." exit $E_NOTFOUND fi MAIL_DIRECTORY=/var/spool/mail/bozo # Uppercase for an environmental export MAIL_DIRECTORY #+ variable. GetAnswer () # Mixed case works well for a { #+ function name, especially prompt=$1 #+ when it improves legibility. echo -n $prompt read answer return $answer } GetAnswer "What is your favorite number? " favorite_number=$? echo $favorite_number _uservariable=23 # Permissible, but not recommended. # It's better for user-defined variables not to start with an underscore. # Leave that for system variables. |
Use exit codes in a systematic and meaningful way.
E_WRONG_ARGS=95 ... ... exit $E_WRONG_ARGS |
Ender suggests using the exit codes in /usr/include/sysexits.h in shell scripts, though these are primarily intended for C and C++ programming.
Use standardized parameter flags for script invocation. Ender proposes the following set of flags.
-a All: Return all information (including hidden file info). -b Brief: Short version, usually for other scripts. -c Copy, concatenate, etc. -d Daily: Use information from the whole day, and not merely information for a specific instance/user. -e Extended/Elaborate: (often does not include hidden file info). -h Help: Verbose usage w/descs, aux info, discussion, help. See also -V. -l Log output of script. -m Manual: Launch man-page for base command. -n Numbers: Numerical data only. -r Recursive: All files in a directory (and/or all sub-dirs). -s Setup & File Maintenance: Config files for this script. -u Usage: List of invocation flags for the script. -v Verbose: Human readable output, more or less formatted. -V Version / License / Copy(right|left) / Contribs (email too). |
See also Section F.1.
Break complex scripts into simpler modules. Use functions where appropriate. See Example 34-4.
Don't use a complex construct where a simpler one will do.
COMMAND if [ $? -eq 0 ] ... # Redundant and non-intuitive. if COMMAND ... # 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. |