The current version of Bash, the one you have running on your machine, is most likely version 2.xx.yy, 3.xx.yy, or 4.xx.yy.
bash$ echo $BASH_VERSION 3.2.25(1)-release |
The version 2 update of the classic Bash scripting language added array variables, string and parameter expansion, and a better method of indirect variable references, among other features.
Example 37-1. String expansion
1 #!/bin/bash 2 3 # String expansion. 4 # Introduced with version 2 of Bash. 5 6 # Strings of the form $'xxx' 7 #+ have the standard escaped characters interpreted. 8 9 echo $'Ringing bell 3 times \a \a \a' 10 # May only ring once with certain terminals. 11 # Or ... 12 # May not ring at all, depending on terminal settings. 13 echo $'Three form feeds \f \f \f' 14 echo $'10 newlines \n\n\n\n\n\n\n\n\n\n' 15 echo $'\102\141\163\150' 16 # B a s h 17 # Octal equivalent of characters. 18 19 exit |
Example 37-2. Indirect variable references - the new way
1 #!/bin/bash
2
3 # Indirect variable referencing.
4 # This has a few of the attributes of references in C++.
5
6
7 a=letter_of_alphabet
8 letter_of_alphabet=z
9
10 echo "a = $a" # Direct reference.
11
12 echo "Now a = ${!a}" # Indirect reference.
13 # The ${!variable} notation is more intuitive than the old
14 #+ eval var1=\$$var2
15
16 echo
17
18 t=table_cell_3
19 table_cell_3=24
20 echo "t = ${!t}" # t = 24
21 table_cell_3=387
22 echo "Value of t changed to ${!t}" # 387
23 # No 'eval' necessary.
24
25 # This is useful for referencing members of an array or table,
26 #+ or for simulating a multi-dimensional array.
27 # An indexing option (analogous to pointer arithmetic)
28 #+ would have been nice. Sigh.
29
30 exit 0
31
32 # See also, ind-ref.sh example. |
Example 37-3. Simple database application, using indirect variable referencing
1 #!/bin/bash
2 # resistor-inventory.sh
3 # Simple database / table-lookup application.
4
5 # ============================================================== #
6 # Data
7
8 B1723_value=470 # Ohms
9 B1723_powerdissip=.25 # Watts
10 B1723_colorcode="yellow-violet-brown" # Color bands
11 B1723_loc=173 # Where they are
12 B1723_inventory=78 # How many
13
14 B1724_value=1000
15 B1724_powerdissip=.25
16 B1724_colorcode="brown-black-red"
17 B1724_loc=24N
18 B1724_inventory=243
19
20 B1725_value=10000
21 B1725_powerdissip=.125
22 B1725_colorcode="brown-black-orange"
23 B1725_loc=24N
24 B1725_inventory=89
25
26 # ============================================================== #
27
28
29 echo
30
31 PS3='Enter catalog number: '
32
33 echo
34
35 select catalog_number in "B1723" "B1724" "B1725"
36 do
37 Inv=${catalog_number}_inventory
38 Val=${catalog_number}_value
39 Pdissip=${catalog_number}_powerdissip
40 Loc=${catalog_number}_loc
41 Ccode=${catalog_number}_colorcode
42
43 echo
44 echo "Catalog number $catalog_number:"
45 # Now, retrieve value, using indirect referencing.
46 echo "There are ${!Inv} of [${!Val} ohm / ${!Pdissip} watt]\
47 resistors in stock." # ^ ^
48 # As of Bash 4.2, you can replace "ohm" with \u2126 (using echo -e).
49 echo "These are located in bin # ${!Loc}."
50 echo "Their color code is \"${!Ccode}\"."
51
52 break
53 done
54
55 echo; echo
56
57 # Exercises:
58 # ---------
59 # 1) Rewrite this script to read its data from an external file.
60 # 2) Rewrite this script to use arrays,
61 #+ rather than indirect variable referencing.
62 # Which method is more straightforward and intuitive?
63 # Which method is easier to code?
64
65
66 # Notes:
67 # -----
68 # Shell scripts are inappropriate for anything except the most simple
69 #+ database applications, and even then it involves workarounds and kludges.
70 # Much better is to use a language with native support for data structures,
71 #+ such as C++ or Java (or even Perl).
72
73 exit 0 |
Example 37-4. Using arrays and other miscellaneous trickery to deal four random hands from a deck of cards
1 #!/bin/bash
2 # cards.sh
3
4 # Deals four random hands from a deck of cards.
5
6 UNPICKED=0
7 PICKED=1
8
9 DUPE_CARD=99
10
11 LOWER_LIMIT=0
12 UPPER_LIMIT=51
13 CARDS_IN_SUIT=13
14 CARDS=52
15
16 declare -a Deck
17 declare -a Suits
18 declare -a Cards
19 # It would have been easier to implement and more intuitive
20 #+ with a single, 3-dimensional array.
21 # Perhaps a future version of Bash will support multidimensional arrays.
22
23
24 initialize_Deck ()
25 {
26 i=$LOWER_LIMIT
27 until [ "$i" -gt $UPPER_LIMIT ]
28 do
29 Deck[i]=$UNPICKED # Set each card of "Deck" as unpicked.
30 let "i += 1"
31 done
32 echo
33 }
34
35 initialize_Suits ()
36 {
37 Suits[0]=C #Clubs
38 Suits[1]=D #Diamonds
39 Suits[2]=H #Hearts
40 Suits[3]=S #Spades
41 }
42
43 initialize_Cards ()
44 {
45 Cards=(2 3 4 5 6 7 8 9 10 J Q K A)
46 # Alternate method of initializing an array.
47 }
48
49 pick_a_card ()
50 {
51 card_number=$RANDOM
52 let "card_number %= $CARDS" # Restrict range to 0 - 51, i.e., 52 cards.
53 if [ "${Deck[card_number]}" -eq $UNPICKED ]
54 then
55 Deck[card_number]=$PICKED
56 return $card_number
57 else
58 return $DUPE_CARD
59 fi
60 }
61
62 parse_card ()
63 {
64 number=$1
65 let "suit_number = number / CARDS_IN_SUIT"
66 suit=${Suits[suit_number]}
67 echo -n "$suit-"
68 let "card_no = number % CARDS_IN_SUIT"
69 Card=${Cards[card_no]}
70 printf %-4s $Card
71 # Print cards in neat columns.
72 }
73
74 seed_random () # Seed random number generator.
75 { # What happens if you don't do this?
76 seed=`eval date +%s`
77 let "seed %= 32766"
78 RANDOM=$seed
79 } # Consider other methods of seeding the random number generator.
80
81 deal_cards ()
82 {
83 echo
84
85 cards_picked=0
86 while [ "$cards_picked" -le $UPPER_LIMIT ]
87 do
88 pick_a_card
89 t=$?
90
91 if [ "$t" -ne $DUPE_CARD ]
92 then
93 parse_card $t
94
95 u=$cards_picked+1
96 # Change back to 1-based indexing, temporarily. Why?
97 let "u %= $CARDS_IN_SUIT"
98 if [ "$u" -eq 0 ] # Nested if/then condition test.
99 then
100 echo
101 echo
102 fi # Each hand set apart with a blank line.
103
104 let "cards_picked += 1"
105 fi
106 done
107
108 echo
109
110 return 0
111 }
112
113
114 # Structured programming:
115 # Entire program logic modularized in functions.
116
117 #===============
118 seed_random
119 initialize_Deck
120 initialize_Suits
121 initialize_Cards
122 deal_cards
123 #===============
124
125 exit
126
127
128
129 # Exercise 1:
130 # Add comments to thoroughly document this script.
131
132 # Exercise 2:
133 # Add a routine (function) to print out each hand sorted in suits.
134 # You may add other bells and whistles if you like.
135
136 # Exercise 3:
137 # Simplify and streamline the logic of the script. |