555 lines
9.2 KiB
HTML
555 lines
9.2 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>Bash, version 2</TITLE
|
|
><META
|
|
NAME="GENERATOR"
|
|
CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK
|
|
REL="HOME"
|
|
TITLE="Advanced Bash-Scripting Guide"
|
|
HREF="index.html"><LINK
|
|
REL="UP"
|
|
TITLE="Bash, versions 2, 3, and 4"
|
|
HREF="bash2.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="Bash, versions 2, 3, and 4"
|
|
HREF="bash2.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="Bash, version 3"
|
|
HREF="bashver3.html"></HEAD
|
|
><BODY
|
|
CLASS="SECT1"
|
|
BGCOLOR="#FFFFFF"
|
|
TEXT="#000000"
|
|
LINK="#0000FF"
|
|
VLINK="#840084"
|
|
ALINK="#0000FF"
|
|
><DIV
|
|
CLASS="NAVHEADER"
|
|
><TABLE
|
|
SUMMARY="Header navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TH
|
|
COLSPAN="3"
|
|
ALIGN="center"
|
|
>Advanced Bash-Scripting Guide: </TH
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="left"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="bash2.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
>Chapter 37. Bash, versions 2, 3, and 4</TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="bashver3.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="SECT1"
|
|
><H1
|
|
CLASS="SECT1"
|
|
><A
|
|
NAME="BASHVER2"
|
|
></A
|
|
>37.1. Bash, version 2</H1
|
|
><P
|
|
><A
|
|
NAME="BASH2REF"
|
|
></A
|
|
></P
|
|
><P
|
|
> The current version of <I
|
|
CLASS="FIRSTTERM"
|
|
>Bash</I
|
|
>, the one
|
|
you have running on your machine, is most likely version 2.xx.yy,
|
|
3.xx.yy, or 4.xx.yy.
|
|
<TABLE
|
|
BORDER="1"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="SCREEN"
|
|
><TT
|
|
CLASS="PROMPT"
|
|
>bash$ </TT
|
|
><TT
|
|
CLASS="USERINPUT"
|
|
><B
|
|
>echo $BASH_VERSION</B
|
|
></TT
|
|
>
|
|
<TT
|
|
CLASS="COMPUTEROUTPUT"
|
|
>3.2.25(1)-release</TT
|
|
>
|
|
</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
</P
|
|
><P
|
|
>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.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="EX77"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-1. String expansion</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/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'
|
|
# May only ring once with certain terminals.
|
|
# Or ...
|
|
# May not ring at all, depending on terminal settings.
|
|
echo $'Three form feeds \f \f \f'
|
|
echo $'10 newlines \n\n\n\n\n\n\n\n\n\n'
|
|
echo $'\102\141\163\150'
|
|
# B a s h
|
|
# Octal equivalent of characters.
|
|
|
|
exit</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
><A
|
|
NAME="VARREFNEW"
|
|
></A
|
|
></P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="EX78"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-2. Indirect variable references - the new way</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/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 more intuitive than 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
|
|
# No 'eval' necessary.
|
|
|
|
# This is useful for referencing members of an array or table,
|
|
#+ or for simulating a multi-dimensional array.
|
|
# An indexing option (analogous to pointer arithmetic)
|
|
#+ would have been nice. Sigh.
|
|
|
|
exit 0
|
|
|
|
# See also, ind-ref.sh example.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="RESISTOR"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-3. Simple database application, using indirect variable
|
|
referencing</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# resistor-inventory.sh
|
|
# Simple database / table-lookup application.
|
|
|
|
# ============================================================== #
|
|
# Data
|
|
|
|
B1723_value=470 # Ohms
|
|
B1723_powerdissip=.25 # Watts
|
|
B1723_colorcode="yellow-violet-brown" # Color bands
|
|
B1723_loc=173 # Where they are
|
|
B1723_inventory=78 # How many
|
|
|
|
B1724_value=1000
|
|
B1724_powerdissip=.25
|
|
B1724_colorcode="brown-black-red"
|
|
B1724_loc=24N
|
|
B1724_inventory=243
|
|
|
|
B1725_value=10000
|
|
B1725_powerdissip=.125
|
|
B1725_colorcode="brown-black-orange"
|
|
B1725_loc=24N
|
|
B1725_inventory=89
|
|
|
|
# ============================================================== #
|
|
|
|
|
|
echo
|
|
|
|
PS3='Enter catalog number: '
|
|
|
|
echo
|
|
|
|
select catalog_number in "B1723" "B1724" "B1725"
|
|
do
|
|
Inv=${catalog_number}_inventory
|
|
Val=${catalog_number}_value
|
|
Pdissip=${catalog_number}_powerdissip
|
|
Loc=${catalog_number}_loc
|
|
Ccode=${catalog_number}_colorcode
|
|
|
|
echo
|
|
echo "Catalog number $catalog_number:"
|
|
# Now, retrieve value, using indirect referencing.
|
|
echo "There are ${!Inv} of [${!Val} ohm / ${!Pdissip} watt]\
|
|
resistors in stock." # ^ ^
|
|
# As of Bash 4.2, you can replace "ohm" with \u2126 (using echo -e).
|
|
echo "These are located in bin # ${!Loc}."
|
|
echo "Their color code is \"${!Ccode}\"."
|
|
|
|
break
|
|
done
|
|
|
|
echo; echo
|
|
|
|
# Exercises:
|
|
# ---------
|
|
# 1) Rewrite this script to read its data from an external file.
|
|
# 2) Rewrite this script to use arrays,
|
|
#+ rather than indirect variable referencing.
|
|
# Which method is more straightforward and intuitive?
|
|
# Which method is easier to code?
|
|
|
|
|
|
# Notes:
|
|
# -----
|
|
# Shell scripts are inappropriate for anything except the most simple
|
|
#+ database applications, and even then it involves workarounds and kludges.
|
|
# Much better is to use a language with native support for data structures,
|
|
#+ such as C++ or Java (or even Perl).
|
|
|
|
exit 0</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="CARDS"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 37-4. Using arrays and other miscellaneous trickery
|
|
to deal four random hands from a deck of cards</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# cards.sh
|
|
|
|
# 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 to implement 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" # Restrict range to 0 - 51, i.e., 52 cards.
|
|
if [ "${Deck[card_number]}" -eq $UNPICKED ]
|
|
then
|
|
Deck[card_number]=$PICKED
|
|
return $card_number
|
|
else
|
|
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.
|
|
{ # What happens if you don't do this?
|
|
seed=`eval date +%s`
|
|
let "seed %= 32766"
|
|
RANDOM=$seed
|
|
} # Consider other methods of seeding the random number generator.
|
|
|
|
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. Why?
|
|
let "u %= $CARDS_IN_SUIT"
|
|
if [ "$u" -eq 0 ] # Nested if/then condition test.
|
|
then
|
|
echo
|
|
echo
|
|
fi # Each hand set apart with a blank line.
|
|
|
|
let "cards_picked += 1"
|
|
fi
|
|
done
|
|
|
|
echo
|
|
|
|
return 0
|
|
}
|
|
|
|
|
|
# Structured programming:
|
|
# Entire program logic modularized in functions.
|
|
|
|
#===============
|
|
seed_random
|
|
initialize_Deck
|
|
initialize_Suits
|
|
initialize_Cards
|
|
deal_cards
|
|
#===============
|
|
|
|
exit
|
|
|
|
|
|
|
|
# Exercise 1:
|
|
# Add comments to thoroughly document this script.
|
|
|
|
# Exercise 2:
|
|
# Add a routine (function) 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.</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></DIV
|
|
><DIV
|
|
CLASS="NAVFOOTER"
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"><TABLE
|
|
SUMMARY="Footer navigation table"
|
|
WIDTH="100%"
|
|
BORDER="0"
|
|
CELLPADDING="0"
|
|
CELLSPACING="0"
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="bash2.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="index.html"
|
|
ACCESSKEY="H"
|
|
>Home</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="bashver3.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Bash, versions 2, 3, and 4</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="bash2.html"
|
|
ACCESSKEY="U"
|
|
>Up</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
>Bash, version 3</TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |