- •Table of Contents
- •Chapter 1. Why Shell Programming?
- •2.1. Invoking the script
- •2.2. Preliminary Exercises
- •Part 2. Basics
- •Chapter 3. Exit and Exit Status
- •Chapter 4. Special Characters
- •Chapter 5. Introduction to Variables and Parameters
- •5.1. Variable Substitution
- •5.2. Variable Assignment
- •5.3. Bash Variables Are Untyped
- •5.4. Special Variable Types
- •Chapter 6. Quoting
- •Chapter 7. Tests
- •7.1. Test Constructs
- •7.2. File test operators
- •7.3. Comparison operators (binary)
- •7.4. Nested if/then Condition Tests
- •7.5. Testing Your Knowledge of Tests
- •Chapter 8. Operations and Related Topics
- •8.1. Operators
- •8.2. Numerical Constants
- •Part 3. Beyond the Basics
- •Chapter 9. Variables Revisited
- •9.1. Internal Variables
- •9.2. Manipulating Strings
- •9.2.1. Manipulating strings using awk
- •9.2.2. Further Discussion
- •9.3. Parameter Substitution
- •9.4. Typing variables: declare or typeset
- •9.5. Indirect References to Variables
- •9.6. $RANDOM: generate random integer
- •9.7. The Double Parentheses Construct
- •Chapter 10. Loops and Branches
- •10.1. Loops
- •10.2. Nested Loops
- •10.3. Loop Control
- •10.4. Testing and Branching
- •Chapter 11. Internal Commands and Builtins
- •11.1. Job Control Commands
- •Chapter 12. External Filters, Programs and Commands
- •12.1. Basic Commands
- •12.2. Complex Commands
- •12.3. Time / Date Commands
- •12.4. Text Processing Commands
- •12.5. File and Archiving Commands
- •12.6. Communications Commands
- •12.7. Terminal Control Commands
- •12.8. Math Commands
- •12.9. Miscellaneous Commands
- •Chapter 13. System and Administrative Commands
- •Chapter 14. Command Substitution
- •Chapter 15. Arithmetic Expansion
- •Chapter 16. I/O Redirection
- •16.1. Using exec
- •16.2. Redirecting Code Blocks
- •16.3. Applications
- •Chapter 17. Here Documents
- •Chapter 18. Recess Time
- •Part 4. Advanced Topics
- •Chapter 19. Regular Expressions
- •19.1. A Brief Introduction to Regular Expressions
- •19.2. Globbing
- •Chapter 20. Subshells
- •Chapter 21. Restricted Shells
- •Chapter 22. Process Substitution
- •Chapter 23. Functions
- •23.1. Complex Functions and Function Complexities
- •23.2. Local Variables
- •23.2.1. Local variables make recursion possible.
- •Chapter 24. Aliases
- •Chapter 25. List Constructs
- •Chapter 26. Arrays
- •Chapter 27. Files
- •Chapter 28. /dev and /proc
- •28.2. /proc
- •Chapter 29. Of Zeros and Nulls
- •Chapter 30. Debugging
- •Chapter 31. Options
- •Chapter 32. Gotchas
- •Chapter 33. Scripting With Style
- •33.1. Unofficial Shell Scripting Stylesheet
- •Chapter 34. Miscellany
- •34.2. Shell Wrappers
- •34.3. Tests and Comparisons: Alternatives
- •34.4. Optimizations
- •34.5. Assorted Tips
- •34.6. Oddities
- •34.7. Portability Issues
- •34.8. Shell Scripting Under Windows
- •Chapter 35. Bash, version 2
- •Chapter 36. Endnotes
- •36.1. Author's Note
- •36.2. About the Author
- •36.3. Tools Used to Produce This Book
- •36.3.1. Hardware
- •36.3.2. Software and Printware
- •36.4. Credits
- •Bibliography
- •Appendix A. Contributed Scripts
- •Appendix C. Exit Codes With Special Meanings
- •Appendix D. A Detailed Introduction to I/O and I/O Redirection
- •Appendix E. Localization
- •Appendix F. History Commands
- •Appendix G. A Sample .bashrc File
- •Appendix H. Converting DOS Batch Files to Shell Scripts
- •Appendix I. Exercises
- •Appendix J. Copyright
Chapter 33. 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.
33.1. Unofficial Shell Scripting Stylesheet
∙ 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. |
|
#************************************************# |
||
BADDIR=65 |
|
# 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, $BADDIR if something went wrong. #−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−# cleanup_pfiles ()
{
if [ ! −d "$1" ] # Test if target directory exists. then
echo "$1 is not a directory." return $BADDIR
fi
rm −f "$1"/*
return 0 # Success.
}
cleanup_pfiles $projectdir
exit 0
Be sure to put the #!/bin/bash at the beginning of the first line of the script, preceding any comment headers.
Chapter 33. Scripting With Style |
296 |
Advanced Bash−Scripting Guide
∙Avoid using "magic numbers", [61] 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=75 |
# Uppercase for an errorcode, |
|
# and name begins 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 variable. |
export MAIL_DIRECTORY |
|
GetAnswer () |
# Mixed case works well for a function. |
{ |
|
prompt=$1 |
|
echo −n $prompt read answer return $answer
}
GetAnswer "What is your favorite number? " favorite_number=$?
echo $favorite_number
_uservariable=23 |
# Permissable, 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=65
...
...
exit $E_WRONG_ARGS
Chapter 33. Scripting With Style |
297 |
Advanced Bash−Scripting Guide
See also Appendix C.
∙Break complex scripts into simpler modules. Use functions where appropriate. See Example 35−3.
∙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).
Chapter 33. Scripting With Style |
298 |