- •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 35. Bash, version 2
The current version of Bash, the one you have running on your machine, is actually version 2.XX.
bash$ echo $BASH_VERSION
2.04.21(1)−release
This update of the classic Bash scripting language added array variables, [62] string and parameter expansion, and a better method of indirect variable references, among other features.
Example 35−1. String expansion
#!/bin/bash
#String expansion.
#Introduced with version 2 of Bash.
#Strings of the form $'xxx'
#have the standard escaped characters interpreted.
echo $'Ringing bell 3 times \a \a \a' echo $'Three form feeds \f \f \f'
echo $'10 newlines \n\n\n\n\n\n\n\n\n\n'
exit 0
Example 35−2. Indirect variable references − the new way
#!/bin/bash
#Indirect variable referencing.
#This has a few of the attributes of references in C++.
a=letter_of_alphabet letter_of_alphabet=z
echo |
"a = |
$a" |
|
# |
Direct reference. |
echo |
"Now |
a = |
${!a}" |
# |
Indirect reference. |
# The ${!variable} notation is greatly superior to the old "eval var1=\$$var2"
echo
t=table_cell_3 table_cell_3=24
echo "t = ${!t}" # t = 24 table_cell_3=387
echo "Value of t changed to ${!t}" # 387
#This is useful for referencing members of an array or table,
#or for simulating a multi−dimensional array.
#An indexing option would have been nice (sigh).
exit 0
Chapter 35. Bash, version 2 |
309 |
Advanced Bash−Scripting Guide
Example 35−3. Using arrays and other miscellaneous trickery to deal four random hands from a deck of cards
#!/bin/bash
# May need to be invoked with #!/bin/bash2 on older machines.
#Cards:
#deals four random hands from a deck of cards.
UNPICKED=0
PICKED=1
DUPE_CARD=99
LOWER_LIMIT=0
UPPER_LIMIT=51
CARDS_IN_SUIT=13
CARDS=52
declare −a Deck declare −a Suits declare −a Cards
#It would have been easier and more intuitive
#with a single, 3−dimensional array.
#Perhaps a future version of Bash will support multidimensional arrays.
initialize_Deck ()
{
i=$LOWER_LIMIT
until [ "$i" −gt $UPPER_LIMIT ] do
Deck[i]=$UNPICKED # Set each card of "Deck" as unpicked. let "i += 1"
done echo
}
initialize_Suits ()
{
Suits[0]=C #Clubs Suits[1]=D #Diamonds Suits[2]=H #Hearts Suits[3]=S #Spades
}
initialize_Cards ()
{
Cards=(2 3 4 5 6 7 8 9 10 J Q K A)
# Alternate method of initializing an array.
}
pick_a_card ()
{
card_number=$RANDOM
let "card_number %= $CARDS"
if [ "${Deck[card_number]}" −eq $UNPICKED ] then
Deck[card_number]=$PICKED return $card_number
else
Chapter 35. Bash, version 2 |
310 |
Advanced Bash−Scripting Guide
return $DUPE_CARD
fi
}
parse_card ()
{
number=$1
let "suit_number = number / CARDS_IN_SUIT" suit=${Suits[suit_number]}
echo −n "$suit−"
let "card_no = number % CARDS_IN_SUIT" Card=${Cards[card_no]}
printf %−4s $Card
# Print cards in neat columns.
}
seed_random () # Seed random number generator.
{
seed=`eval date +%s` let "seed %= 32766" RANDOM=$seed
}
deal_cards ()
{
echo
cards_picked=0
while [ "$cards_picked" −le $UPPER_LIMIT ] do
pick_a_card t=$?
if [ "$t" −ne $DUPE_CARD ] then
parse_card $t
u=$cards_picked+1
# Change back to 1−based indexing (temporarily). let "u %= $CARDS_IN_SUIT"
if [ "$u" −eq 0 ] |
# Nested if/then condition test. |
then |
|
echo |
|
echo |
|
fi |
|
# Separate hands. |
|
let "cards_picked += 1"
fi done
echo
return 0
}
#Structured programming:
#entire program logic modularized in functions.
#================ seed_random
Chapter 35. Bash, version 2 |
311 |
Advanced Bash−Scripting Guide
initialize_Deck initialize_Suits initialize_Cards deal_cards
exit 0 #================
#Exercise 1:
#Add comments to thoroughly document this script.
#Exercise 2:
#Revise the script to print out each hand sorted in suits.
#You may add other bells and whistles if you like.
#Exercise 3:
#Simplify and streamline the logic of the script.
Chapter 35. Bash, version 2 |
312 |