old-www/LDP/abs/html/bashver2.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
>