1096 lines
17 KiB
HTML
1096 lines
17 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||
<HTML
|
||
><HEAD
|
||
><TITLE
|
||
>Testing and Branching</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="Loops and Branches"
|
||
HREF="loops.html"><LINK
|
||
REL="PREVIOUS"
|
||
TITLE="Loop Control"
|
||
HREF="loopcontrol.html"><LINK
|
||
REL="NEXT"
|
||
TITLE="Command Substitution"
|
||
HREF="commandsub.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="loopcontrol.html"
|
||
ACCESSKEY="P"
|
||
>Prev</A
|
||
></TD
|
||
><TD
|
||
WIDTH="80%"
|
||
ALIGN="center"
|
||
VALIGN="bottom"
|
||
>Chapter 11. Loops and Branches</TD
|
||
><TD
|
||
WIDTH="10%"
|
||
ALIGN="right"
|
||
VALIGN="bottom"
|
||
><A
|
||
HREF="commandsub.html"
|
||
ACCESSKEY="N"
|
||
>Next</A
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
><HR
|
||
ALIGN="LEFT"
|
||
WIDTH="100%"></DIV
|
||
><DIV
|
||
CLASS="SECT1"
|
||
><H1
|
||
CLASS="SECT1"
|
||
><A
|
||
NAME="TESTBRANCH"
|
||
></A
|
||
>11.4. Testing and Branching</H1
|
||
><P
|
||
>The <B
|
||
CLASS="COMMAND"
|
||
>case</B
|
||
> and <B
|
||
CLASS="COMMAND"
|
||
>select</B
|
||
>
|
||
constructs are technically not loops, since they do not iterate the
|
||
execution of a code block. Like loops, however, they direct
|
||
program flow according to conditions at the top or bottom of
|
||
the block.</P
|
||
><P
|
||
></P
|
||
><DIV
|
||
CLASS="VARIABLELIST"
|
||
><P
|
||
><B
|
||
><A
|
||
NAME="CASEESAC1"
|
||
></A
|
||
>Controlling program flow in a code
|
||
block</B
|
||
></P
|
||
><DL
|
||
><DT
|
||
><B
|
||
CLASS="COMMAND"
|
||
>case (in) / esac</B
|
||
></DT
|
||
><DD
|
||
><P
|
||
>The <B
|
||
CLASS="COMMAND"
|
||
>case</B
|
||
> construct is the shell
|
||
scripting analog to <TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>switch</I
|
||
></TT
|
||
>
|
||
in <B
|
||
CLASS="COMMAND"
|
||
>C/C++</B
|
||
>.
|
||
It permits branching to one of a number of code blocks,
|
||
depending on condition tests. It serves as a kind of
|
||
shorthand for multiple <SPAN
|
||
CLASS="TOKEN"
|
||
>if/then/else</SPAN
|
||
>
|
||
statements and is an appropriate tool for creating
|
||
menus.</P
|
||
><P
|
||
><P
|
||
><B
|
||
CLASS="COMMAND"
|
||
>case</B
|
||
> "$<TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>variable</I
|
||
></TT
|
||
>" in <BR><BR> <20>"$<TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>condition1</I
|
||
></TT
|
||
>" ) <BR> <20><TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>command</I
|
||
></TT
|
||
>... <BR> <20>;; <BR><BR> <20>"$<TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>condition2</I
|
||
></TT
|
||
>" ) <BR> <20><TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>command</I
|
||
></TT
|
||
>... <BR> <20>;; <BR><BR><BR><B
|
||
CLASS="COMMAND"
|
||
>esac</B
|
||
> </P
|
||
></P
|
||
><DIV
|
||
CLASS="NOTE"
|
||
><P
|
||
></P
|
||
><TABLE
|
||
CLASS="NOTE"
|
||
WIDTH="90%"
|
||
BORDER="0"
|
||
><TR
|
||
><TD
|
||
WIDTH="25"
|
||
ALIGN="CENTER"
|
||
VALIGN="TOP"
|
||
><IMG
|
||
SRC="../images/note.gif"
|
||
HSPACE="5"
|
||
ALT="Note"></TD
|
||
><TD
|
||
ALIGN="LEFT"
|
||
VALIGN="TOP"
|
||
><P
|
||
> <P
|
||
></P
|
||
><UL
|
||
><LI
|
||
><P
|
||
>Quoting the variables is not mandatory,
|
||
since word splitting does not take place.</P
|
||
></LI
|
||
><LI
|
||
><P
|
||
><A
|
||
NAME="CASEPAREN"
|
||
></A
|
||
>Each test line
|
||
ends with a right paren <B
|
||
CLASS="COMMAND"
|
||
>)</B
|
||
>.
|
||
|
||
<A
|
||
NAME="AEN7087"
|
||
HREF="#FTN.AEN7087"
|
||
><SPAN
|
||
CLASS="footnote"
|
||
>[1]</SPAN
|
||
></A
|
||
>
|
||
</P
|
||
></LI
|
||
><LI
|
||
><P
|
||
>Each condition block ends
|
||
with a <EM
|
||
>double</EM
|
||
> semicolon
|
||
<SPAN
|
||
CLASS="TOKEN"
|
||
>;;</SPAN
|
||
>.</P
|
||
></LI
|
||
><LI
|
||
><P
|
||
>If a condition tests
|
||
<I
|
||
CLASS="FIRSTTERM"
|
||
>true</I
|
||
>, then the associated
|
||
commands execute and the <B
|
||
CLASS="COMMAND"
|
||
>case</B
|
||
>
|
||
block terminates.</P
|
||
></LI
|
||
><LI
|
||
><P
|
||
>The entire <B
|
||
CLASS="COMMAND"
|
||
>case</B
|
||
>
|
||
block ends with an <B
|
||
CLASS="COMMAND"
|
||
>esac</B
|
||
>
|
||
(<I
|
||
CLASS="WORDASWORD"
|
||
>case</I
|
||
> spelled backwards).</P
|
||
></LI
|
||
></UL
|
||
>
|
||
</P
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
><DIV
|
||
CLASS="EXAMPLE"
|
||
><A
|
||
NAME="EX29"
|
||
></A
|
||
><P
|
||
><B
|
||
>Example 11-25. Using <I
|
||
CLASS="FIRSTTERM"
|
||
>case</I
|
||
></B
|
||
></P
|
||
><TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#!/bin/bash
|
||
# Testing ranges of characters.
|
||
|
||
echo; echo "Hit a key, then hit return."
|
||
read Keypress
|
||
|
||
case "$Keypress" in
|
||
[[:lower:]] ) echo "Lowercase letter";;
|
||
[[:upper:]] ) echo "Uppercase letter";;
|
||
[0-9] ) echo "Digit";;
|
||
* ) echo "Punctuation, whitespace, or other";;
|
||
esac # Allows ranges of characters in [square brackets],
|
||
#+ or POSIX ranges in [[double square brackets.
|
||
|
||
# In the first version of this example,
|
||
#+ the tests for lowercase and uppercase characters were
|
||
#+ [a-z] and [A-Z].
|
||
# This no longer works in certain locales and/or Linux distros.
|
||
# POSIX is more portable.
|
||
# Thanks to Frank Wang for pointing this out.
|
||
|
||
# Exercise:
|
||
# --------
|
||
# As the script stands, it accepts a single keystroke, then terminates.
|
||
# Change the script so it accepts repeated input,
|
||
#+ reports on each keystroke, and terminates only when "X" is hit.
|
||
# Hint: enclose everything in a "while" loop.
|
||
|
||
exit 0</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
><DIV
|
||
CLASS="EXAMPLE"
|
||
><A
|
||
NAME="EX30"
|
||
></A
|
||
><P
|
||
><B
|
||
>Example 11-26. Creating menus using <I
|
||
CLASS="FIRSTTERM"
|
||
>case</I
|
||
></B
|
||
></P
|
||
><TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#!/bin/bash
|
||
|
||
# Crude address database
|
||
|
||
clear # Clear the screen.
|
||
|
||
echo " Contact List"
|
||
echo " ------- ----"
|
||
echo "Choose one of the following persons:"
|
||
echo
|
||
echo "[E]vans, Roland"
|
||
echo "[J]ones, Mildred"
|
||
echo "[S]mith, Julie"
|
||
echo "[Z]ane, Morris"
|
||
echo
|
||
|
||
read person
|
||
|
||
case "$person" in
|
||
# Note variable is quoted.
|
||
|
||
"E" | "e" )
|
||
# Accept upper or lowercase input.
|
||
echo
|
||
echo "Roland Evans"
|
||
echo "4321 Flash Dr."
|
||
echo "Hardscrabble, CO 80753"
|
||
echo "(303) 734-9874"
|
||
echo "(303) 734-9892 fax"
|
||
echo "revans@zzy.net"
|
||
echo "Business partner & old friend"
|
||
;;
|
||
# Note double semicolon to terminate each option.
|
||
|
||
"J" | "j" )
|
||
echo
|
||
echo "Mildred Jones"
|
||
echo "249 E. 7th St., Apt. 19"
|
||
echo "New York, NY 10009"
|
||
echo "(212) 533-2814"
|
||
echo "(212) 533-9972 fax"
|
||
echo "milliej@loisaida.com"
|
||
echo "Ex-girlfriend"
|
||
echo "Birthday: Feb. 11"
|
||
;;
|
||
|
||
# Add info for Smith & Zane later.
|
||
|
||
* )
|
||
# Default option.
|
||
# Empty input (hitting RETURN) fits here, too.
|
||
echo
|
||
echo "Not yet in database."
|
||
;;
|
||
|
||
esac
|
||
|
||
echo
|
||
|
||
# Exercise:
|
||
# --------
|
||
# Change the script so it accepts multiple inputs,
|
||
#+ instead of terminating after displaying just one address.
|
||
|
||
exit 0</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
><P
|
||
><A
|
||
NAME="CASECL"
|
||
></A
|
||
></P
|
||
><P
|
||
>An exceptionally clever use of <B
|
||
CLASS="COMMAND"
|
||
>case</B
|
||
>
|
||
involves testing for command-line parameters.
|
||
<TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#! /bin/bash
|
||
|
||
case "$1" in
|
||
"") echo "Usage: ${0##*/} <filename>"; exit $E_PARAM;;
|
||
# No command-line parameters,
|
||
# or first parameter empty.
|
||
# Note that ${0##*/} is ${var##pattern} param substitution.
|
||
# Net result is $0.
|
||
|
||
-*) FILENAME=./$1;; # If filename passed as argument ($1)
|
||
#+ starts with a dash,
|
||
#+ replace it with ./$1
|
||
#+ so further commands don't interpret it
|
||
#+ as an option.
|
||
|
||
* ) FILENAME=$1;; # Otherwise, $1.
|
||
esac</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></P
|
||
><P
|
||
>Here is a more straightforward example of
|
||
command-line parameter handling:
|
||
<TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#! /bin/bash
|
||
|
||
|
||
while [ $# -gt 0 ]; do # Until you run out of parameters . . .
|
||
case "$1" in
|
||
-d|--debug)
|
||
# "-d" or "--debug" parameter?
|
||
DEBUG=1
|
||
;;
|
||
-c|--conf)
|
||
CONFFILE="$2"
|
||
shift
|
||
if [ ! -f $CONFFILE ]; then
|
||
echo "Error: Supplied file doesn't exist!"
|
||
exit $E_CONFFILE # File not found error.
|
||
fi
|
||
;;
|
||
esac
|
||
shift # Check next set of parameters.
|
||
done
|
||
|
||
# From Stefano Falsetto's "Log2Rot" script,
|
||
#+ part of his "rottlog" package.
|
||
# Used with permission.</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></P
|
||
><DIV
|
||
CLASS="EXAMPLE"
|
||
><A
|
||
NAME="CASECMD"
|
||
></A
|
||
><P
|
||
><B
|
||
>Example 11-27. Using <I
|
||
CLASS="FIRSTTERM"
|
||
>command substitution</I
|
||
>
|
||
to generate the <I
|
||
CLASS="FIRSTTERM"
|
||
>case</I
|
||
> variable</B
|
||
></P
|
||
><TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#!/bin/bash
|
||
# case-cmd.sh: Using command substitution to generate a "case" variable.
|
||
|
||
case $( arch ) in # $( arch ) returns machine architecture.
|
||
# Equivalent to 'uname -m' ...
|
||
i386 ) echo "80386-based machine";;
|
||
i486 ) echo "80486-based machine";;
|
||
i586 ) echo "Pentium-based machine";;
|
||
i686 ) echo "Pentium2+-based machine";;
|
||
* ) echo "Other type of machine";;
|
||
esac
|
||
|
||
exit 0</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
><P
|
||
><A
|
||
NAME="CSGLOB"
|
||
></A
|
||
></P
|
||
><P
|
||
>A <B
|
||
CLASS="COMMAND"
|
||
>case</B
|
||
> construct can filter strings for
|
||
<A
|
||
HREF="globbingref.html"
|
||
>globbing</A
|
||
> patterns.</P
|
||
><DIV
|
||
CLASS="EXAMPLE"
|
||
><A
|
||
NAME="MATCHSTRING"
|
||
></A
|
||
><P
|
||
><B
|
||
>Example 11-28. Simple string matching</B
|
||
></P
|
||
><TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#!/bin/bash
|
||
# match-string.sh: Simple string matching
|
||
# using a 'case' construct.
|
||
|
||
match_string ()
|
||
{ # Exact string match.
|
||
MATCH=0
|
||
E_NOMATCH=90
|
||
PARAMS=2 # Function requires 2 arguments.
|
||
E_BAD_PARAMS=91
|
||
|
||
[ $# -eq $PARAMS ] || return $E_BAD_PARAMS
|
||
|
||
case "$1" in
|
||
"$2") return $MATCH;;
|
||
* ) return $E_NOMATCH;;
|
||
esac
|
||
|
||
}
|
||
|
||
|
||
a=one
|
||
b=two
|
||
c=three
|
||
d=two
|
||
|
||
|
||
match_string $a # wrong number of parameters
|
||
echo $? # 91
|
||
|
||
match_string $a $b # no match
|
||
echo $? # 90
|
||
|
||
match_string $b $d # match
|
||
echo $? # 0
|
||
|
||
|
||
exit 0 </PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
><DIV
|
||
CLASS="EXAMPLE"
|
||
><A
|
||
NAME="ISALPHA"
|
||
></A
|
||
><P
|
||
><B
|
||
>Example 11-29. Checking for alphabetic input</B
|
||
></P
|
||
><TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#!/bin/bash
|
||
# isalpha.sh: Using a "case" structure to filter a string.
|
||
|
||
SUCCESS=0
|
||
FAILURE=1 # Was FAILURE=-1,
|
||
#+ but Bash no longer allows negative return value.
|
||
|
||
isalpha () # Tests whether *first character* of input string is alphabetic.
|
||
{
|
||
if [ -z "$1" ] # No argument passed?
|
||
then
|
||
return $FAILURE
|
||
fi
|
||
|
||
case "$1" in
|
||
[a-zA-Z]*) return $SUCCESS;; # Begins with a letter?
|
||
* ) return $FAILURE;;
|
||
esac
|
||
} # Compare this with "isalpha ()" function in C.
|
||
|
||
|
||
isalpha2 () # Tests whether *entire string* is alphabetic.
|
||
{
|
||
[ $# -eq 1 ] || return $FAILURE
|
||
|
||
case $1 in
|
||
*[!a-zA-Z]*|"") return $FAILURE;;
|
||
*) return $SUCCESS;;
|
||
esac
|
||
}
|
||
|
||
isdigit () # Tests whether *entire string* is numerical.
|
||
{ # In other words, tests for integer variable.
|
||
[ $# -eq 1 ] || return $FAILURE
|
||
|
||
case $1 in
|
||
*[!0-9]*|"") return $FAILURE;;
|
||
*) return $SUCCESS;;
|
||
esac
|
||
}
|
||
|
||
|
||
|
||
check_var () # Front-end to isalpha ().
|
||
{
|
||
if isalpha "$@"
|
||
then
|
||
echo "\"$*\" begins with an alpha character."
|
||
if isalpha2 "$@"
|
||
then # No point in testing if first char is non-alpha.
|
||
echo "\"$*\" contains only alpha characters."
|
||
else
|
||
echo "\"$*\" contains at least one non-alpha character."
|
||
fi
|
||
else
|
||
echo "\"$*\" begins with a non-alpha character."
|
||
# Also "non-alpha" if no argument passed.
|
||
fi
|
||
|
||
echo
|
||
|
||
}
|
||
|
||
digit_check () # Front-end to isdigit ().
|
||
{
|
||
if isdigit "$@"
|
||
then
|
||
echo "\"$*\" contains only digits [0 - 9]."
|
||
else
|
||
echo "\"$*\" has at least one non-digit character."
|
||
fi
|
||
|
||
echo
|
||
|
||
}
|
||
|
||
a=23skidoo
|
||
b=H3llo
|
||
c=-What?
|
||
d=What?
|
||
e=$(echo $b) # Command substitution.
|
||
f=AbcDef
|
||
g=27234
|
||
h=27a34
|
||
i=27.34
|
||
|
||
check_var $a
|
||
check_var $b
|
||
check_var $c
|
||
check_var $d
|
||
check_var $e
|
||
check_var $f
|
||
check_var # No argument passed, so what happens?
|
||
#
|
||
digit_check $g
|
||
digit_check $h
|
||
digit_check $i
|
||
|
||
|
||
exit 0 # Script improved by S.C.
|
||
|
||
# Exercise:
|
||
# --------
|
||
# Write an 'isfloat ()' function that tests for floating point numbers.
|
||
# Hint: The function duplicates 'isdigit ()',
|
||
#+ but adds a test for a mandatory decimal point.</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
></DD
|
||
><DT
|
||
><A
|
||
NAME="SELECTREF"
|
||
></A
|
||
><B
|
||
CLASS="COMMAND"
|
||
>select</B
|
||
></DT
|
||
><DD
|
||
><P
|
||
>The <B
|
||
CLASS="COMMAND"
|
||
>select</B
|
||
> construct, adopted from the Korn
|
||
Shell, is yet another tool for building menus.</P
|
||
><P
|
||
><P
|
||
><B
|
||
CLASS="COMMAND"
|
||
>select</B
|
||
> <TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>variable</I
|
||
></TT
|
||
> [in <TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>list</I
|
||
></TT
|
||
>]<BR> do <BR> <20><TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>command</I
|
||
></TT
|
||
>... <BR> <20>break <BR> done </P
|
||
></P
|
||
><P
|
||
>This prompts the user to enter one of the choices presented in the
|
||
variable list. Note that <B
|
||
CLASS="COMMAND"
|
||
>select</B
|
||
> uses the
|
||
<TT
|
||
CLASS="VARNAME"
|
||
>$PS3</TT
|
||
> prompt (<TT
|
||
CLASS="PROMPT"
|
||
>#? </TT
|
||
>) by default,
|
||
but this may be changed.</P
|
||
><DIV
|
||
CLASS="EXAMPLE"
|
||
><A
|
||
NAME="EX31"
|
||
></A
|
||
><P
|
||
><B
|
||
>Example 11-30. Creating menus using <I
|
||
CLASS="FIRSTTERM"
|
||
>select</I
|
||
></B
|
||
></P
|
||
><TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#!/bin/bash
|
||
|
||
PS3='Choose your favorite vegetable: ' # Sets the prompt string.
|
||
# Otherwise it defaults to #? .
|
||
|
||
echo
|
||
|
||
select vegetable in "beans" "carrots" "potatoes" "onions" "rutabagas"
|
||
do
|
||
echo
|
||
echo "Your favorite veggie is $vegetable."
|
||
echo "Yuck!"
|
||
echo
|
||
break # What happens if there is no 'break' here?
|
||
done
|
||
|
||
exit
|
||
|
||
# Exercise:
|
||
# --------
|
||
# Fix this script to accept user input not specified in
|
||
#+ the "select" statement.
|
||
# For example, if the user inputs "peas,"
|
||
#+ the script would respond "Sorry. That is not on the menu."</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
><P
|
||
><A
|
||
NAME="INLISTOMIT"
|
||
></A
|
||
></P
|
||
><P
|
||
>If <TT
|
||
CLASS="USERINPUT"
|
||
><B
|
||
>in <TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>list</I
|
||
></TT
|
||
></B
|
||
></TT
|
||
> is
|
||
omitted, then <B
|
||
CLASS="COMMAND"
|
||
>select</B
|
||
> uses the list of command
|
||
line arguments (<TT
|
||
CLASS="VARNAME"
|
||
>$@</TT
|
||
>) passed to the script or
|
||
the function containing the <B
|
||
CLASS="COMMAND"
|
||
>select</B
|
||
>
|
||
construct.</P
|
||
><P
|
||
>Compare this to the behavior of a
|
||
<P
|
||
><B
|
||
CLASS="COMMAND"
|
||
>for</B
|
||
> <TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>variable</I
|
||
></TT
|
||
> [in <TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>list</I
|
||
></TT
|
||
>]</P
|
||
>
|
||
construct with the
|
||
<TT
|
||
CLASS="USERINPUT"
|
||
><B
|
||
>in <TT
|
||
CLASS="REPLACEABLE"
|
||
><I
|
||
>list</I
|
||
></TT
|
||
></B
|
||
></TT
|
||
>
|
||
omitted.</P
|
||
><DIV
|
||
CLASS="EXAMPLE"
|
||
><A
|
||
NAME="EX32"
|
||
></A
|
||
><P
|
||
><B
|
||
>Example 11-31. Creating menus using <I
|
||
CLASS="FIRSTTERM"
|
||
>select</I
|
||
>
|
||
in a function</B
|
||
></P
|
||
><TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>#!/bin/bash
|
||
|
||
PS3='Choose your favorite vegetable: '
|
||
|
||
echo
|
||
|
||
choice_of()
|
||
{
|
||
select vegetable
|
||
# [in list] omitted, so 'select' uses arguments passed to function.
|
||
do
|
||
echo
|
||
echo "Your favorite veggie is $vegetable."
|
||
echo "Yuck!"
|
||
echo
|
||
break
|
||
done
|
||
}
|
||
|
||
choice_of beans rice carrots radishes rutabaga spinach
|
||
# $1 $2 $3 $4 $5 $6
|
||
# passed to choice_of() function
|
||
|
||
exit 0</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
><P
|
||
>See also <A
|
||
HREF="bashver2.html#RESISTOR"
|
||
>Example 37-3</A
|
||
>.</P
|
||
></DD
|
||
></DL
|
||
></DIV
|
||
></DIV
|
||
><H3
|
||
CLASS="FOOTNOTES"
|
||
>Notes</H3
|
||
><TABLE
|
||
BORDER="0"
|
||
CLASS="FOOTNOTES"
|
||
WIDTH="100%"
|
||
><TR
|
||
><TD
|
||
ALIGN="LEFT"
|
||
VALIGN="TOP"
|
||
WIDTH="5%"
|
||
><A
|
||
NAME="FTN.AEN7087"
|
||
HREF="testbranch.html#AEN7087"
|
||
><SPAN
|
||
CLASS="footnote"
|
||
>[1]</SPAN
|
||
></A
|
||
></TD
|
||
><TD
|
||
ALIGN="LEFT"
|
||
VALIGN="TOP"
|
||
WIDTH="95%"
|
||
><P
|
||
>Pattern-match lines may also <EM
|
||
>start</EM
|
||
>
|
||
with a <B
|
||
CLASS="COMMAND"
|
||
>(</B
|
||
> left paren to give the layout
|
||
a more structured appearance.</P
|
||
><P
|
||
><TABLE
|
||
BORDER="0"
|
||
BGCOLOR="#E0E0E0"
|
||
WIDTH="90%"
|
||
><TR
|
||
><TD
|
||
><FONT
|
||
COLOR="#000000"
|
||
><PRE
|
||
CLASS="PROGRAMLISTING"
|
||
>case $( arch ) in # $( arch ) returns machine architecture.
|
||
( i386 ) echo "80386-based machine";;
|
||
# ^ ^
|
||
( i486 ) echo "80486-based machine";;
|
||
( i586 ) echo "Pentium-based machine";;
|
||
( i686 ) echo "Pentium2+-based machine";;
|
||
( * ) echo "Other type of machine";;
|
||
esac</PRE
|
||
></FONT
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
></P
|
||
></TD
|
||
></TR
|
||
></TABLE
|
||
><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="loopcontrol.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="commandsub.html"
|
||
ACCESSKEY="N"
|
||
>Next</A
|
||
></TD
|
||
></TR
|
||
><TR
|
||
><TD
|
||
WIDTH="33%"
|
||
ALIGN="left"
|
||
VALIGN="top"
|
||
>Loop Control</TD
|
||
><TD
|
||
WIDTH="34%"
|
||
ALIGN="center"
|
||
VALIGN="top"
|
||
><A
|
||
HREF="loops.html"
|
||
ACCESSKEY="U"
|
||
>Up</A
|
||
></TD
|
||
><TD
|
||
WIDTH="33%"
|
||
ALIGN="right"
|
||
VALIGN="top"
|
||
>Command Substitution</TD
|
||
></TR
|
||
></TABLE
|
||
></DIV
|
||
></BODY
|
||
></HTML
|
||
> |