2286 lines
34 KiB
HTML
2286 lines
34 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|||
|
<HTML
|
|||
|
><HEAD
|
|||
|
><TITLE
|
|||
|
>Loops</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="Loops and Branches"
|
|||
|
HREF="loops.html"><LINK
|
|||
|
REL="NEXT"
|
|||
|
TITLE="Nested Loops"
|
|||
|
HREF="nestedloops.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="loops.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="nestedloops.html"
|
|||
|
ACCESSKEY="N"
|
|||
|
>Next</A
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
><HR
|
|||
|
ALIGN="LEFT"
|
|||
|
WIDTH="100%"></DIV
|
|||
|
><DIV
|
|||
|
CLASS="SECT1"
|
|||
|
><H1
|
|||
|
CLASS="SECT1"
|
|||
|
><A
|
|||
|
NAME="LOOPS1"
|
|||
|
></A
|
|||
|
>11.1. Loops</H1
|
|||
|
><P
|
|||
|
>A <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>loop</I
|
|||
|
> is a block of code that
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>iterates</I
|
|||
|
>
|
|||
|
|
|||
|
<A
|
|||
|
NAME="AEN6560"
|
|||
|
HREF="#FTN.AEN6560"
|
|||
|
><SPAN
|
|||
|
CLASS="footnote"
|
|||
|
>[1]</SPAN
|
|||
|
></A
|
|||
|
>
|
|||
|
|
|||
|
a list of commands
|
|||
|
as long as the <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>loop control condition</I
|
|||
|
>
|
|||
|
is true.</P
|
|||
|
><P
|
|||
|
></P
|
|||
|
><DIV
|
|||
|
CLASS="VARIABLELIST"
|
|||
|
><P
|
|||
|
><B
|
|||
|
><A
|
|||
|
NAME="FORLOOPREF1"
|
|||
|
></A
|
|||
|
>for loops</B
|
|||
|
></P
|
|||
|
><DL
|
|||
|
><DT
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>for <TT
|
|||
|
CLASS="PARAMETER"
|
|||
|
><I
|
|||
|
>arg</I
|
|||
|
></TT
|
|||
|
> in
|
|||
|
<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
>[list]</I
|
|||
|
></TT
|
|||
|
></B
|
|||
|
></DT
|
|||
|
><DD
|
|||
|
><P
|
|||
|
>This is the basic looping construct. It differs significantly
|
|||
|
from its <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>C</I
|
|||
|
> counterpart.</P
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="DOINREF"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
><P
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>for</B
|
|||
|
> <TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
>arg</I
|
|||
|
></TT
|
|||
|
> in [<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
>list</I
|
|||
|
></TT
|
|||
|
>]<BR> do <BR> <TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
><3E>command(s)</I
|
|||
|
></TT
|
|||
|
>... <BR> done </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
|
|||
|
>During each pass through the loop,
|
|||
|
<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
>arg</I
|
|||
|
></TT
|
|||
|
> takes on the
|
|||
|
value of each successive variable in the
|
|||
|
<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
>list</I
|
|||
|
></TT
|
|||
|
>.</P
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>for arg in "$var1" "$var2" "$var3" ... "$varN"
|
|||
|
# In pass 1 of the loop, arg = $var1
|
|||
|
# In pass 2 of the loop, arg = $var2
|
|||
|
# In pass 3 of the loop, arg = $var3
|
|||
|
# ...
|
|||
|
# In pass N of the loop, arg = $varN
|
|||
|
|
|||
|
# Arguments in [list] quoted to prevent possible word splitting.</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></P
|
|||
|
><P
|
|||
|
>The argument <TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
>list</I
|
|||
|
></TT
|
|||
|
> may
|
|||
|
contain <A
|
|||
|
HREF="special-chars.html#ASTERISKREF"
|
|||
|
>wild cards</A
|
|||
|
>.</P
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="NEEDSEMICOLON"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>If <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>do</I
|
|||
|
> is on same line as
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
>, there needs to be a semicolon
|
|||
|
after list.</P
|
|||
|
><P
|
|||
|
><P
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>for</B
|
|||
|
> <TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
>arg</I
|
|||
|
></TT
|
|||
|
> in [<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
>list</I
|
|||
|
></TT
|
|||
|
>] ; do <BR></P
|
|||
|
></P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="EX22"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-1. Simple <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loops</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# Listing the planets.
|
|||
|
|
|||
|
for planet in Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto
|
|||
|
do
|
|||
|
echo $planet # Each planet on a separate line.
|
|||
|
done
|
|||
|
|
|||
|
echo; echo
|
|||
|
|
|||
|
for planet in "Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune Pluto"
|
|||
|
# All planets on same line.
|
|||
|
# Entire 'list' enclosed in quotes creates a single variable.
|
|||
|
# Why? Whitespace incorporated into the variable.
|
|||
|
do
|
|||
|
echo $planet
|
|||
|
done
|
|||
|
|
|||
|
echo; echo "Whoops! Pluto is no longer a planet!"
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="MULTPARAML"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>Each <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
> element
|
|||
|
may contain multiple parameters. This is useful when
|
|||
|
processing parameters in groups. In such cases,
|
|||
|
use the <A
|
|||
|
HREF="internal.html#SETREF"
|
|||
|
>set</A
|
|||
|
> command
|
|||
|
(see <A
|
|||
|
HREF="internal.html#EX34"
|
|||
|
>Example 15-16</A
|
|||
|
>) to force parsing of each
|
|||
|
<TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
> element and assignment of
|
|||
|
each component to the positional parameters.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="EX22A"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-2. <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loop with two parameters in each
|
|||
|
[list] element</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# Planets revisited.
|
|||
|
|
|||
|
# Associate the name of each planet with its distance from the sun.
|
|||
|
|
|||
|
for planet in "Mercury 36" "Venus 67" "Earth 93" "Mars 142" "Jupiter 483"
|
|||
|
do
|
|||
|
set -- $planet # Parses variable "planet"
|
|||
|
#+ and sets positional parameters.
|
|||
|
# The "--" prevents nasty surprises if $planet is null or
|
|||
|
#+ begins with a dash.
|
|||
|
|
|||
|
# May need to save original positional parameters,
|
|||
|
#+ since they get overwritten.
|
|||
|
# One way of doing this is to use an array,
|
|||
|
# original_params=("$@")
|
|||
|
|
|||
|
echo "$1 $2,000,000 miles from the sun"
|
|||
|
#-------two tabs---concatenate zeroes onto parameter $2
|
|||
|
done
|
|||
|
|
|||
|
# (Thanks, S.C., for additional clarification.)
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="PARAMLI"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>A variable may supply the <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
> in a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loop</I
|
|||
|
>.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="FILEINFO"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-3. <EM
|
|||
|
>Fileinfo:</EM
|
|||
|
> operating on a file list
|
|||
|
contained in a variable</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# fileinfo.sh
|
|||
|
|
|||
|
FILES="/usr/sbin/accept
|
|||
|
/usr/sbin/pwck
|
|||
|
/usr/sbin/chroot
|
|||
|
/usr/bin/fakefile
|
|||
|
/sbin/badblocks
|
|||
|
/sbin/ypbind" # List of files you are curious about.
|
|||
|
# Threw in a dummy file, /usr/bin/fakefile.
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
for file in $FILES
|
|||
|
do
|
|||
|
|
|||
|
if [ ! -e "$file" ] # Check if file exists.
|
|||
|
then
|
|||
|
echo "$file does not exist."; echo
|
|||
|
continue # On to next.
|
|||
|
fi
|
|||
|
|
|||
|
ls -l $file | awk '{ print $8 " file size: " $5 }' # Print 2 fields.
|
|||
|
whatis `basename $file` # File info.
|
|||
|
# Note that the whatis database needs to have been set up for this to work.
|
|||
|
# To do this, as root run /usr/bin/makewhatis.
|
|||
|
echo
|
|||
|
done
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="PARAMLI2"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>The <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
> in a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loop</I
|
|||
|
> may be parameterized.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="FILEINFO01"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-4. Operating on a parameterized file list</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
|
|||
|
filename="*txt"
|
|||
|
|
|||
|
for file in $filename
|
|||
|
do
|
|||
|
echo "Contents of $file"
|
|||
|
echo "---"
|
|||
|
cat "$file"
|
|||
|
echo
|
|||
|
done</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="LIGLOB"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>If the <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
> in a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loop</I
|
|||
|
> contains wild cards
|
|||
|
(<SPAN
|
|||
|
CLASS="TOKEN"
|
|||
|
>*</SPAN
|
|||
|
> and <SPAN
|
|||
|
CLASS="TOKEN"
|
|||
|
>?</SPAN
|
|||
|
>) used in filename
|
|||
|
expansion, then <A
|
|||
|
HREF="globbingref.html"
|
|||
|
>globbing</A
|
|||
|
>
|
|||
|
takes place.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="LISTGLOB"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-5. Operating on files with a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loop</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# list-glob.sh: Generating [list] in a for-loop, using "globbing" ...
|
|||
|
# Globbing = filename expansion.
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
for file in *
|
|||
|
# ^ Bash performs filename expansion
|
|||
|
#+ on expressions that globbing recognizes.
|
|||
|
do
|
|||
|
ls -l "$file" # Lists all files in $PWD (current directory).
|
|||
|
# Recall that the wild card character "*" matches every filename,
|
|||
|
#+ however, in "globbing," it doesn't match dot-files.
|
|||
|
|
|||
|
# If the pattern matches no file, it is expanded to itself.
|
|||
|
# To prevent this, set the nullglob option
|
|||
|
#+ (shopt -s nullglob).
|
|||
|
# Thanks, S.C.
|
|||
|
done
|
|||
|
|
|||
|
echo; echo
|
|||
|
|
|||
|
for file in [jx]*
|
|||
|
do
|
|||
|
rm -f $file # Removes only files beginning with "j" or "x" in $PWD.
|
|||
|
echo "Removed file \"$file\"".
|
|||
|
done
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="OMITLIST"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>Omitting the <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>in [list]</B
|
|||
|
></TT
|
|||
|
> part of a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loop</I
|
|||
|
> causes the loop to operate
|
|||
|
on <SPAN
|
|||
|
CLASS="TOKEN"
|
|||
|
>$@</SPAN
|
|||
|
> -- the <A
|
|||
|
HREF="internalvariables.html#POSPARAMREF"
|
|||
|
> positional parameters</A
|
|||
|
>. A particularly clever
|
|||
|
illustration of this is <A
|
|||
|
HREF="contributed-scripts.html#PRIMES"
|
|||
|
>Example A-15</A
|
|||
|
>. See also <A
|
|||
|
HREF="internal.html#REVPOSPARAMS"
|
|||
|
>Example 15-17</A
|
|||
|
>.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="EX23"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-6. Missing <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>in [list]</B
|
|||
|
></TT
|
|||
|
> in a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loop</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
|
|||
|
# Invoke this script both with and without arguments,
|
|||
|
#+ and see what happens.
|
|||
|
|
|||
|
for a
|
|||
|
do
|
|||
|
echo -n "$a "
|
|||
|
done
|
|||
|
|
|||
|
# The 'in list' missing, therefore the loop operates on '$@'
|
|||
|
#+ (command-line argument list, including whitespace).
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="LOOPCS"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>It is possible to use <A
|
|||
|
HREF="commandsub.html#COMMANDSUBREF"
|
|||
|
>command substitution</A
|
|||
|
>
|
|||
|
to generate the <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
> in a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loop</I
|
|||
|
>. See also <A
|
|||
|
HREF="extmisc.html#EX53"
|
|||
|
>Example 16-54</A
|
|||
|
>,
|
|||
|
<A
|
|||
|
HREF="loops1.html#SYMLINKS"
|
|||
|
>Example 11-11</A
|
|||
|
> and <A
|
|||
|
HREF="mathc.html#BASE"
|
|||
|
>Example 16-48</A
|
|||
|
>.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="FORLOOPCMD"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-7. Generating the <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
> in
|
|||
|
a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loop with command substitution</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# for-loopcmd.sh: for-loop with [list]
|
|||
|
#+ generated by command substitution.
|
|||
|
|
|||
|
NUMBERS="9 7 3 8 37.53"
|
|||
|
|
|||
|
for number in `echo $NUMBERS` # for number in 9 7 3 8 37.53
|
|||
|
do
|
|||
|
echo -n "$number "
|
|||
|
done
|
|||
|
|
|||
|
echo
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
>Here is a somewhat more complex example of using command
|
|||
|
substitution to create the <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
>.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="BINGREP"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-8. A <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>grep</I
|
|||
|
> replacement
|
|||
|
for binary files</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# bin-grep.sh: Locates matching strings in a binary file.
|
|||
|
|
|||
|
# A "grep" replacement for binary files.
|
|||
|
# Similar effect to "grep -a"
|
|||
|
|
|||
|
E_BADARGS=65
|
|||
|
E_NOFILE=66
|
|||
|
|
|||
|
if [ $# -ne 2 ]
|
|||
|
then
|
|||
|
echo "Usage: `basename $0` search_string filename"
|
|||
|
exit $E_BADARGS
|
|||
|
fi
|
|||
|
|
|||
|
if [ ! -f "$2" ]
|
|||
|
then
|
|||
|
echo "File \"$2\" does not exist."
|
|||
|
exit $E_NOFILE
|
|||
|
fi
|
|||
|
|
|||
|
|
|||
|
IFS=$'\012' # Per suggestion of Anton Filippov.
|
|||
|
# was: IFS="\n"
|
|||
|
for word in $( strings "$2" | grep "$1" )
|
|||
|
# The "strings" command lists strings in binary files.
|
|||
|
# Output then piped to "grep", which tests for desired string.
|
|||
|
do
|
|||
|
echo $word
|
|||
|
done
|
|||
|
|
|||
|
# As S.C. points out, lines 23 - 30 could be replaced with the simpler
|
|||
|
# strings "$2" | grep "$1" | tr -s "$IFS" '[\n*]'
|
|||
|
|
|||
|
|
|||
|
# Try something like "./bin-grep.sh mem /bin/ls"
|
|||
|
#+ to exercise this script.
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
>More of the same.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="USERLIST"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-9. Listing all users on the system</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# userlist.sh
|
|||
|
|
|||
|
PASSWORD_FILE=/etc/passwd
|
|||
|
n=1 # User number
|
|||
|
|
|||
|
for name in $(awk 'BEGIN{FS=":"}{print $1}' < "$PASSWORD_FILE" )
|
|||
|
# Field separator = : ^^^^^^
|
|||
|
# Print first field ^^^^^^^^
|
|||
|
# Get input from password file /etc/passwd ^^^^^^^^^^^^^^^^^
|
|||
|
do
|
|||
|
echo "USER #$n = $name"
|
|||
|
let "n += 1"
|
|||
|
done
|
|||
|
|
|||
|
|
|||
|
# USER #1 = root
|
|||
|
# USER #2 = bin
|
|||
|
# USER #3 = daemon
|
|||
|
# ...
|
|||
|
# USER #33 = bozo
|
|||
|
|
|||
|
exit $?
|
|||
|
|
|||
|
# Discussion:
|
|||
|
# ----------
|
|||
|
# How is it that an ordinary user, or a script run by same,
|
|||
|
#+ can read /etc/passwd? (Hint: Check the /etc/passwd file permissions.)
|
|||
|
# Is this a security hole? Why or why not?</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
>Yet another example of the <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
>
|
|||
|
resulting from command substitution.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="FINDSTRING"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-10. Checking all the binaries in a directory for
|
|||
|
authorship</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# findstring.sh:
|
|||
|
# Find a particular string in the binaries in a specified directory.
|
|||
|
|
|||
|
directory=/usr/bin/
|
|||
|
fstring="Free Software Foundation" # See which files come from the FSF.
|
|||
|
|
|||
|
for file in $( find $directory -type f -name '*' | sort )
|
|||
|
do
|
|||
|
strings -f $file | grep "$fstring" | sed -e "s%$directory%%"
|
|||
|
# In the "sed" expression,
|
|||
|
#+ it is necessary to substitute for the normal "/" delimiter
|
|||
|
#+ because "/" happens to be one of the characters filtered out.
|
|||
|
# Failure to do so gives an error message. (Try it.)
|
|||
|
done
|
|||
|
|
|||
|
exit $?
|
|||
|
|
|||
|
# Exercise (easy):
|
|||
|
# ---------------
|
|||
|
# Convert this script to take command-line parameters
|
|||
|
#+ for $directory and $fstring.</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
>A final example of <TT
|
|||
|
CLASS="USERINPUT"
|
|||
|
><B
|
|||
|
>[list]</B
|
|||
|
></TT
|
|||
|
>
|
|||
|
/ command substitution, but this time
|
|||
|
the <SPAN
|
|||
|
CLASS="QUOTE"
|
|||
|
>"command"</SPAN
|
|||
|
> is a <A
|
|||
|
HREF="functions.html#FUNCTIONREF"
|
|||
|
>function</A
|
|||
|
>.</P
|
|||
|
><P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>generate_list ()
|
|||
|
{
|
|||
|
echo "one two three"
|
|||
|
}
|
|||
|
|
|||
|
for word in $(generate_list) # Let "word" grab output of function.
|
|||
|
do
|
|||
|
echo "$word"
|
|||
|
done
|
|||
|
|
|||
|
# one
|
|||
|
# two
|
|||
|
# three</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></P
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="LOOPREDIR"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>The output of a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loop</I
|
|||
|
> may
|
|||
|
be piped to a command or commands.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="SYMLINKS"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-11. Listing the <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>symbolic
|
|||
|
links</I
|
|||
|
> in a directory</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# symlinks.sh: Lists symbolic links in a directory.
|
|||
|
|
|||
|
|
|||
|
directory=${1-`pwd`}
|
|||
|
# Defaults to current working directory,
|
|||
|
#+ if not otherwise specified.
|
|||
|
# Equivalent to code block below.
|
|||
|
# ----------------------------------------------------------
|
|||
|
# ARGS=1 # Expect one command-line argument.
|
|||
|
#
|
|||
|
# if [ $# -ne "$ARGS" ] # If not 1 arg...
|
|||
|
# then
|
|||
|
# directory=`pwd` # current working directory
|
|||
|
# else
|
|||
|
# directory=$1
|
|||
|
# fi
|
|||
|
# ----------------------------------------------------------
|
|||
|
|
|||
|
echo "symbolic links in directory \"$directory\""
|
|||
|
|
|||
|
for file in "$( find $directory -type l )" # -type l = symbolic links
|
|||
|
do
|
|||
|
echo "$file"
|
|||
|
done | sort # Otherwise file list is unsorted.
|
|||
|
# Strictly speaking, a loop isn't really necessary here,
|
|||
|
#+ since the output of the "find" command is expanded into a single word.
|
|||
|
# However, it's easy to understand and illustrative this way.
|
|||
|
|
|||
|
# As Dominik 'Aeneas' Schnitzer points out,
|
|||
|
#+ failing to quote $( find $directory -type l )
|
|||
|
#+ will choke on filenames with embedded whitespace.
|
|||
|
# containing whitespace.
|
|||
|
|
|||
|
exit 0
|
|||
|
|
|||
|
|
|||
|
# --------------------------------------------------------
|
|||
|
# Jean Helou proposes the following alternative:
|
|||
|
|
|||
|
echo "symbolic links in directory \"$directory\""
|
|||
|
# Backup of the current IFS. One can never be too cautious.
|
|||
|
OLDIFS=$IFS
|
|||
|
IFS=:
|
|||
|
|
|||
|
for file in $(find $directory -type l -printf "%p$IFS")
|
|||
|
do # ^^^^^^^^^^^^^^^^
|
|||
|
echo "$file"
|
|||
|
done|sort
|
|||
|
|
|||
|
# And, James "Mike" Conley suggests modifying Helou's code thusly:
|
|||
|
|
|||
|
OLDIFS=$IFS
|
|||
|
IFS='' # Null IFS means no word breaks
|
|||
|
for file in $( find $directory -type l )
|
|||
|
do
|
|||
|
echo $file
|
|||
|
done | sort
|
|||
|
|
|||
|
# This works in the "pathological" case of a directory name having
|
|||
|
#+ an embedded colon.
|
|||
|
# "This also fixes the pathological case of the directory name having
|
|||
|
#+ a colon (or space in earlier example) as well." </PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
>The <TT
|
|||
|
CLASS="FILENAME"
|
|||
|
>stdout</TT
|
|||
|
> of a loop may be <A
|
|||
|
HREF="io-redirection.html#IOREDIRREF"
|
|||
|
>redirected</A
|
|||
|
> to a file, as this slight
|
|||
|
modification to the previous example shows.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="SYMLINKS2"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-12. Symbolic links in a directory, saved to a file</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# symlinks.sh: Lists symbolic links in a directory.
|
|||
|
|
|||
|
OUTFILE=symlinks.list # save-file
|
|||
|
|
|||
|
directory=${1-`pwd`}
|
|||
|
# Defaults to current working directory,
|
|||
|
#+ if not otherwise specified.
|
|||
|
|
|||
|
|
|||
|
echo "symbolic links in directory \"$directory\"" > "$OUTFILE"
|
|||
|
echo "---------------------------" >> "$OUTFILE"
|
|||
|
|
|||
|
for file in "$( find $directory -type l )" # -type l = symbolic links
|
|||
|
do
|
|||
|
echo "$file"
|
|||
|
done | sort >> "$OUTFILE" # stdout of loop
|
|||
|
# ^^^^^^^^^^^^^ redirected to save file.
|
|||
|
|
|||
|
# echo "Output file = $OUTFILE"
|
|||
|
|
|||
|
exit $?</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="LOOPCSTYLE"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>There is an alternative syntax to a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for
|
|||
|
loop</I
|
|||
|
> that will look very familiar to C
|
|||
|
programmers. This requires <A
|
|||
|
HREF="dblparens.html#DBLPARENSREF"
|
|||
|
>double parentheses</A
|
|||
|
>.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="FORLOOPC"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-13. A C-style <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loop</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# Multiple ways to count up to 10.
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
# Standard syntax.
|
|||
|
for a in 1 2 3 4 5 6 7 8 9 10
|
|||
|
do
|
|||
|
echo -n "$a "
|
|||
|
done
|
|||
|
|
|||
|
echo; echo
|
|||
|
|
|||
|
# +==========================================+
|
|||
|
|
|||
|
# Using "seq" ...
|
|||
|
for a in `seq 10`
|
|||
|
do
|
|||
|
echo -n "$a "
|
|||
|
done
|
|||
|
|
|||
|
echo; echo
|
|||
|
|
|||
|
# +==========================================+
|
|||
|
|
|||
|
# Using brace expansion ...
|
|||
|
# Bash, version 3+.
|
|||
|
for a in {1..10}
|
|||
|
do
|
|||
|
echo -n "$a "
|
|||
|
done
|
|||
|
|
|||
|
echo; echo
|
|||
|
|
|||
|
# +==========================================+
|
|||
|
|
|||
|
# Now, let's do the same, using C-like syntax.
|
|||
|
|
|||
|
LIMIT=10
|
|||
|
|
|||
|
for ((a=1; a <= LIMIT ; a++)) # Double parentheses, and naked "LIMIT"
|
|||
|
do
|
|||
|
echo -n "$a "
|
|||
|
done # A construct borrowed from ksh93.
|
|||
|
|
|||
|
echo; echo
|
|||
|
|
|||
|
# +=========================================================================+
|
|||
|
|
|||
|
# Let's use the C "comma operator" to increment two variables simultaneously.
|
|||
|
|
|||
|
for ((a=1, b=1; a <= LIMIT ; a++, b++))
|
|||
|
do # The comma concatenates operations.
|
|||
|
echo -n "$a-$b "
|
|||
|
done
|
|||
|
|
|||
|
echo; echo
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
>See also <A
|
|||
|
HREF="arrays.html#QFUNCTION"
|
|||
|
>Example 27-16</A
|
|||
|
>, <A
|
|||
|
HREF="arrays.html#TWODIM"
|
|||
|
>Example 27-17</A
|
|||
|
>, and <A
|
|||
|
HREF="contributed-scripts.html#COLLATZ"
|
|||
|
>Example A-6</A
|
|||
|
>.</P
|
|||
|
><P
|
|||
|
>---</P
|
|||
|
><P
|
|||
|
>Now, a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loop</I
|
|||
|
> used in a
|
|||
|
<SPAN
|
|||
|
CLASS="QUOTE"
|
|||
|
>"real-life"</SPAN
|
|||
|
> context.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="EX24"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-14. Using <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>efax</I
|
|||
|
> in batch mode</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# Faxing (must have 'efax' package installed).
|
|||
|
|
|||
|
EXPECTED_ARGS=2
|
|||
|
E_BADARGS=85
|
|||
|
MODEM_PORT="/dev/ttyS2" # May be different on your machine.
|
|||
|
# ^^^^^ PCMCIA modem card default port.
|
|||
|
|
|||
|
if [ $# -ne $EXPECTED_ARGS ]
|
|||
|
# Check for proper number of command-line args.
|
|||
|
then
|
|||
|
echo "Usage: `basename $0` phone# text-file"
|
|||
|
exit $E_BADARGS
|
|||
|
fi
|
|||
|
|
|||
|
|
|||
|
if [ ! -f "$2" ]
|
|||
|
then
|
|||
|
echo "File $2 is not a text file."
|
|||
|
# File is not a regular file, or does not exist.
|
|||
|
exit $E_BADARGS
|
|||
|
fi
|
|||
|
|
|||
|
|
|||
|
fax make $2 # Create fax-formatted files from text files.
|
|||
|
|
|||
|
for file in $(ls $2.0*) # Concatenate the converted files.
|
|||
|
# Uses wild card (filename "globbing")
|
|||
|
#+ in variable list.
|
|||
|
do
|
|||
|
fil="$fil $file"
|
|||
|
done
|
|||
|
|
|||
|
efax -d "$MODEM_PORT" -t "T$1" $fil # Finally, do the work.
|
|||
|
# Trying adding -o1 if above line fails.
|
|||
|
|
|||
|
|
|||
|
# As S.C. points out, the for-loop can be eliminated with
|
|||
|
# efax -d /dev/ttyS2 -o1 -t "T$1" $2.0*
|
|||
|
#+ but it's not quite as instructive [grin].
|
|||
|
|
|||
|
exit $? # Also, efax sends diagnostic messages to stdout.</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><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
|
|||
|
><A
|
|||
|
NAME="NODODONE"
|
|||
|
></A
|
|||
|
>The
|
|||
|
<A
|
|||
|
HREF="internal.html#KEYWORDREF"
|
|||
|
>keywords</A
|
|||
|
>
|
|||
|
<B
|
|||
|
CLASS="COMMAND"
|
|||
|
>do</B
|
|||
|
> and <B
|
|||
|
CLASS="COMMAND"
|
|||
|
>done</B
|
|||
|
> delineate
|
|||
|
the <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for-loop</I
|
|||
|
> command block. However,
|
|||
|
these may, in certain contexts, be omitted by framing the
|
|||
|
command block within <A
|
|||
|
HREF="special-chars.html#CODEBLOCKREF"
|
|||
|
>curly
|
|||
|
brackets</A
|
|||
|
>
|
|||
|
|
|||
|
<TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>for((n=1; n<=10; n++))
|
|||
|
# No do!
|
|||
|
{
|
|||
|
echo -n "* $n *"
|
|||
|
}
|
|||
|
# No done!
|
|||
|
|
|||
|
|
|||
|
# Outputs:
|
|||
|
# * 1 ** 2 ** 3 ** 4 ** 5 ** 6 ** 7 ** 8 ** 9 ** 10 *
|
|||
|
# And, echo $? returns 0, so Bash does not register an error.
|
|||
|
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
|
|||
|
# But, note that in a classic for-loop: for n in [list] ...
|
|||
|
#+ a terminal semicolon is required.
|
|||
|
|
|||
|
for n in 1 2 3
|
|||
|
{ echo -n "$n "; }
|
|||
|
# ^
|
|||
|
|
|||
|
|
|||
|
# Thank you, YongYe, for pointing this out.</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
>
|
|||
|
</P
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
></DD
|
|||
|
><DT
|
|||
|
><A
|
|||
|
NAME="WHILELOOPREF"
|
|||
|
></A
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>while</B
|
|||
|
></DT
|
|||
|
><DD
|
|||
|
><P
|
|||
|
>This construct tests for a condition at the top of a
|
|||
|
loop, and keeps looping as long as that condition
|
|||
|
is true (returns a <SPAN
|
|||
|
CLASS="RETURNVALUE"
|
|||
|
>0</SPAN
|
|||
|
> <A
|
|||
|
HREF="exit-status.html#EXITSTATUSREF"
|
|||
|
>exit status</A
|
|||
|
>). In contrast
|
|||
|
to a <A
|
|||
|
HREF="loops1.html#FORLOOPREF1"
|
|||
|
>for loop</A
|
|||
|
>, a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while loop</I
|
|||
|
> finds use in situations
|
|||
|
where the number of loop repetitions is not known
|
|||
|
beforehand.</P
|
|||
|
><P
|
|||
|
><P
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>while</B
|
|||
|
> [<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
> condition </I
|
|||
|
></TT
|
|||
|
>]<BR> do <BR> <TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
><3E>command(s)</I
|
|||
|
></TT
|
|||
|
>... <BR> done </P
|
|||
|
></P
|
|||
|
><P
|
|||
|
>The bracket construct in a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while
|
|||
|
loop</I
|
|||
|
> is nothing more than our old friend,
|
|||
|
the <A
|
|||
|
HREF="testconstructs.html#TESTCONSTRUCTS1"
|
|||
|
>test brackets</A
|
|||
|
>
|
|||
|
used in an <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>if/then</I
|
|||
|
> test. In fact,
|
|||
|
a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while loop</I
|
|||
|
> can legally use the
|
|||
|
more versatile <A
|
|||
|
HREF="testconstructs.html#DBLBRACKETS"
|
|||
|
>double-brackets
|
|||
|
construct</A
|
|||
|
> (while [[ condition ]]).</P
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="WHILENEEDSEMI"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
><A
|
|||
|
HREF="loops1.html#NEEDSEMICOLON"
|
|||
|
>As is the case with
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loops</I
|
|||
|
></A
|
|||
|
>, placing the
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>do</I
|
|||
|
> on the same line as the condition
|
|||
|
test requires a semicolon.</P
|
|||
|
><P
|
|||
|
><P
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>while</B
|
|||
|
> [<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
> condition </I
|
|||
|
></TT
|
|||
|
>] ; do </P
|
|||
|
></P
|
|||
|
><P
|
|||
|
>Note that the <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>test brackets</I
|
|||
|
>
|
|||
|
<A
|
|||
|
HREF="loops1.html#WHILENOBRACKETS"
|
|||
|
>are <EM
|
|||
|
>not</EM
|
|||
|
>
|
|||
|
mandatory</A
|
|||
|
> in a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while</I
|
|||
|
> loop.
|
|||
|
See, for example, the <A
|
|||
|
HREF="internal.html#GETOPTSX"
|
|||
|
>getopts
|
|||
|
construct</A
|
|||
|
>.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="EX25"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-15. Simple <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while</I
|
|||
|
> loop</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
|
|||
|
var0=0
|
|||
|
LIMIT=10
|
|||
|
|
|||
|
while [ "$var0" -lt "$LIMIT" ]
|
|||
|
# ^ ^
|
|||
|
# Spaces, because these are "test-brackets" . . .
|
|||
|
do
|
|||
|
echo -n "$var0 " # -n suppresses newline.
|
|||
|
# ^ Space, to separate printed out numbers.
|
|||
|
|
|||
|
var0=`expr $var0 + 1` # var0=$(($var0+1)) also works.
|
|||
|
# var0=$((var0 + 1)) also works.
|
|||
|
# let "var0 += 1" also works.
|
|||
|
done # Various other methods also work.
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="EX26"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-16. Another <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while</I
|
|||
|
> loop</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
|
|||
|
echo
|
|||
|
# Equivalent to:
|
|||
|
while [ "$var1" != "end" ] # while test "$var1" != "end"
|
|||
|
do
|
|||
|
echo "Input variable #1 (end to exit) "
|
|||
|
read var1 # Not 'read $var1' (why?).
|
|||
|
echo "variable #1 = $var1" # Need quotes because of "#" . . .
|
|||
|
# If input is 'end', echoes it here.
|
|||
|
# Does not test for termination condition until top of loop.
|
|||
|
echo
|
|||
|
done
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="WHMULTCOND"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>A <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while loop</I
|
|||
|
> may have multiple
|
|||
|
conditions. Only the final condition determines when the loop
|
|||
|
terminates. This necessitates a slightly different loop syntax,
|
|||
|
however.</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="EX26A"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-17. <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while</I
|
|||
|
> loop with multiple conditions</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
|
|||
|
var1=unset
|
|||
|
previous=$var1
|
|||
|
|
|||
|
while echo "previous-variable = $previous"
|
|||
|
echo
|
|||
|
previous=$var1
|
|||
|
[ "$var1" != end ] # Keeps track of what $var1 was previously.
|
|||
|
# Four conditions on *while*, but only the final one controls loop.
|
|||
|
# The *last* exit status is the one that counts.
|
|||
|
do
|
|||
|
echo "Input variable #1 (end to exit) "
|
|||
|
read var1
|
|||
|
echo "variable #1 = $var1"
|
|||
|
done
|
|||
|
|
|||
|
# Try to figure out how this all works.
|
|||
|
# It's a wee bit tricky.
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="WLOOPCSTYLE"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>As with a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loop</I
|
|||
|
>, a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while loop</I
|
|||
|
> may employ C-style syntax
|
|||
|
by using the double-parentheses construct (see also <A
|
|||
|
HREF="dblparens.html#CVARS"
|
|||
|
>Example 8-5</A
|
|||
|
>).</P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="WHLOOPC"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-18. C-style syntax in a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while</I
|
|||
|
> loop</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
# wh-loopc.sh: Count to 10 in a "while" loop.
|
|||
|
|
|||
|
LIMIT=10 # 10 iterations.
|
|||
|
a=1
|
|||
|
|
|||
|
while [ "$a" -le $LIMIT ]
|
|||
|
do
|
|||
|
echo -n "$a "
|
|||
|
let "a+=1"
|
|||
|
done # No surprises, so far.
|
|||
|
|
|||
|
echo; echo
|
|||
|
|
|||
|
# +=================================================================+
|
|||
|
|
|||
|
# Now, we'll repeat with C-like syntax.
|
|||
|
|
|||
|
((a = 1)) # a=1
|
|||
|
# Double parentheses permit space when setting a variable, as in C.
|
|||
|
|
|||
|
while (( a <= LIMIT )) # Double parentheses,
|
|||
|
do #+ and no "$" preceding variables.
|
|||
|
echo -n "$a "
|
|||
|
((a += 1)) # let "a+=1"
|
|||
|
# Yes, indeed.
|
|||
|
# Double parentheses permit incrementing a variable with C-like syntax.
|
|||
|
done
|
|||
|
|
|||
|
echo
|
|||
|
|
|||
|
# C and Java programmers can feel right at home in Bash.
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="WHILEFUNC"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
> Inside its test brackets, a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while loop</I
|
|||
|
>
|
|||
|
can call a <A
|
|||
|
HREF="functions.html#FUNCTIONREF"
|
|||
|
>function</A
|
|||
|
>.
|
|||
|
|
|||
|
<TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>t=0
|
|||
|
|
|||
|
condition ()
|
|||
|
{
|
|||
|
((t++))
|
|||
|
|
|||
|
if [ $t -lt 5 ]
|
|||
|
then
|
|||
|
return 0 # true
|
|||
|
else
|
|||
|
return 1 # false
|
|||
|
fi
|
|||
|
}
|
|||
|
|
|||
|
while condition
|
|||
|
# ^^^^^^^^^
|
|||
|
# Function call -- four loop iterations.
|
|||
|
do
|
|||
|
echo "Still going: t = $t"
|
|||
|
done
|
|||
|
|
|||
|
# Still going: t = 1
|
|||
|
# Still going: t = 2
|
|||
|
# Still going: t = 3
|
|||
|
# Still going: t = 4</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
</P
|
|||
|
><TABLE
|
|||
|
CLASS="SIDEBAR"
|
|||
|
BORDER="1"
|
|||
|
CELLPADDING="5"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><DIV
|
|||
|
CLASS="SIDEBAR"
|
|||
|
><A
|
|||
|
NAME="AEN6856"
|
|||
|
></A
|
|||
|
><P
|
|||
|
></P
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="WHILENOBRACKETS"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>Similar to the <A
|
|||
|
HREF="testconstructs.html#IFGREPREF"
|
|||
|
>if-test</A
|
|||
|
>
|
|||
|
construct, a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while</I
|
|||
|
> loop can omit the test
|
|||
|
brackets.
|
|||
|
<TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>while condition
|
|||
|
do
|
|||
|
command(s) ...
|
|||
|
done</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></P
|
|||
|
><P
|
|||
|
></P
|
|||
|
></DIV
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="WHILEREADREF2"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>By coupling the power of the <A
|
|||
|
HREF="internal.html#READREF"
|
|||
|
>read</A
|
|||
|
> command with a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while loop</I
|
|||
|
>, we get the handy <A
|
|||
|
HREF="internal.html#WHILEREADREF"
|
|||
|
>while read</A
|
|||
|
> construct, useful
|
|||
|
for reading and parsing files.</P
|
|||
|
><P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>cat $filename | # Supply input from a file.
|
|||
|
while read line # As long as there is another line to read ...
|
|||
|
do
|
|||
|
...
|
|||
|
done
|
|||
|
|
|||
|
# =========== Snippet from "sd.sh" example script ========== #
|
|||
|
|
|||
|
while read value # Read one data point at a time.
|
|||
|
do
|
|||
|
rt=$(echo "scale=$SC; $rt + $value" | bc)
|
|||
|
(( ct++ ))
|
|||
|
done
|
|||
|
|
|||
|
am=$(echo "scale=$SC; $rt / $ct" | bc)
|
|||
|
|
|||
|
echo $am; return $ct # This function "returns" TWO values!
|
|||
|
# Caution: This little trick will not work if $ct > 255!
|
|||
|
# To handle a larger number of data points,
|
|||
|
#+ simply comment out the "return $ct" above.
|
|||
|
} <"$datafile" # Feed in data file.</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></P
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="WHREDIR"
|
|||
|
></A
|
|||
|
></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
|
|||
|
>A <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while loop</I
|
|||
|
> may have its
|
|||
|
<TT
|
|||
|
CLASS="FILENAME"
|
|||
|
>stdin</TT
|
|||
|
> <A
|
|||
|
HREF="redircb.html#REDIRREF"
|
|||
|
>redirected to a file</A
|
|||
|
> by a
|
|||
|
<SPAN
|
|||
|
CLASS="TOKEN"
|
|||
|
><</SPAN
|
|||
|
> at its end.</P
|
|||
|
><P
|
|||
|
>A <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while loop</I
|
|||
|
> may have its
|
|||
|
<TT
|
|||
|
CLASS="FILENAME"
|
|||
|
>stdin</TT
|
|||
|
> <A
|
|||
|
HREF="internal.html#READPIPEREF"
|
|||
|
> supplied by a pipe</A
|
|||
|
>.</P
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
></DD
|
|||
|
><DT
|
|||
|
><A
|
|||
|
NAME="UNTILLOOPREF"
|
|||
|
></A
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>until</B
|
|||
|
></DT
|
|||
|
><DD
|
|||
|
><P
|
|||
|
>This construct tests for a condition at the top of a loop, and keeps
|
|||
|
looping as long as that condition is
|
|||
|
<EM
|
|||
|
>false</EM
|
|||
|
> (opposite of <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while
|
|||
|
loop</I
|
|||
|
>).</P
|
|||
|
><P
|
|||
|
><P
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>until</B
|
|||
|
> [<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
> condition-is-true </I
|
|||
|
></TT
|
|||
|
>]<BR> do <BR> <TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
><3E>command(s)</I
|
|||
|
></TT
|
|||
|
>... <BR> done </P
|
|||
|
></P
|
|||
|
><P
|
|||
|
>Note that an <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>until loop</I
|
|||
|
> tests for the
|
|||
|
terminating condition at the <EM
|
|||
|
>top</EM
|
|||
|
>
|
|||
|
of the loop, differing from a similar construct in some
|
|||
|
programming languages.</P
|
|||
|
><P
|
|||
|
>As is the case with <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for loops</I
|
|||
|
>,
|
|||
|
placing the <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>do</I
|
|||
|
> on the same line as
|
|||
|
the condition test requires a semicolon.</P
|
|||
|
><P
|
|||
|
><P
|
|||
|
><B
|
|||
|
CLASS="COMMAND"
|
|||
|
>until</B
|
|||
|
> [<TT
|
|||
|
CLASS="REPLACEABLE"
|
|||
|
><I
|
|||
|
> condition-is-true </I
|
|||
|
></TT
|
|||
|
>] ; do </P
|
|||
|
></P
|
|||
|
><DIV
|
|||
|
CLASS="EXAMPLE"
|
|||
|
><A
|
|||
|
NAME="EX27"
|
|||
|
></A
|
|||
|
><P
|
|||
|
><B
|
|||
|
>Example 11-19. <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>until</I
|
|||
|
> loop</B
|
|||
|
></P
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
BGCOLOR="#E0E0E0"
|
|||
|
WIDTH="90%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
><FONT
|
|||
|
COLOR="#000000"
|
|||
|
><PRE
|
|||
|
CLASS="PROGRAMLISTING"
|
|||
|
>#!/bin/bash
|
|||
|
|
|||
|
END_CONDITION=end
|
|||
|
|
|||
|
until [ "$var1" = "$END_CONDITION" ]
|
|||
|
# Tests condition here, at top of loop.
|
|||
|
do
|
|||
|
echo "Input variable #1 "
|
|||
|
echo "($END_CONDITION to exit)"
|
|||
|
read var1
|
|||
|
echo "variable #1 = $var1"
|
|||
|
echo
|
|||
|
done
|
|||
|
|
|||
|
# --- #
|
|||
|
|
|||
|
# As with "for" and "while" loops,
|
|||
|
#+ an "until" loop permits C-like test constructs.
|
|||
|
|
|||
|
LIMIT=10
|
|||
|
var=0
|
|||
|
|
|||
|
until (( var > LIMIT ))
|
|||
|
do # ^^ ^ ^ ^^ No brackets, no $ prefixing variables.
|
|||
|
echo -n "$var "
|
|||
|
(( var++ ))
|
|||
|
done # 0 1 2 3 4 5 6 7 8 9 10
|
|||
|
|
|||
|
|
|||
|
exit 0</PRE
|
|||
|
></FONT
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
></DD
|
|||
|
></DL
|
|||
|
></DIV
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="CHOOSELOOP"
|
|||
|
></A
|
|||
|
></P
|
|||
|
><P
|
|||
|
>How to choose between a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loop or a
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while</I
|
|||
|
> loop or
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>until</I
|
|||
|
> loop? In <B
|
|||
|
CLASS="COMMAND"
|
|||
|
>C</B
|
|||
|
>,
|
|||
|
you would typically use a <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loop
|
|||
|
when the number of loop iterations is known beforehand. With
|
|||
|
<I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>Bash</I
|
|||
|
>, however, the situation is
|
|||
|
fuzzier. The Bash <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>for</I
|
|||
|
> loop is more
|
|||
|
loosely structured and more flexible than its equivalent in
|
|||
|
other languages. Therefore, feel free to use whatever type
|
|||
|
of loop gets the job done in the simplest way.</P
|
|||
|
></DIV
|
|||
|
><H3
|
|||
|
CLASS="FOOTNOTES"
|
|||
|
>Notes</H3
|
|||
|
><TABLE
|
|||
|
BORDER="0"
|
|||
|
CLASS="FOOTNOTES"
|
|||
|
WIDTH="100%"
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
ALIGN="LEFT"
|
|||
|
VALIGN="TOP"
|
|||
|
WIDTH="5%"
|
|||
|
><A
|
|||
|
NAME="FTN.AEN6560"
|
|||
|
HREF="loops1.html#AEN6560"
|
|||
|
><SPAN
|
|||
|
CLASS="footnote"
|
|||
|
>[1]</SPAN
|
|||
|
></A
|
|||
|
></TD
|
|||
|
><TD
|
|||
|
ALIGN="LEFT"
|
|||
|
VALIGN="TOP"
|
|||
|
WIDTH="95%"
|
|||
|
><P
|
|||
|
><A
|
|||
|
NAME="ITERATIONREF"
|
|||
|
></A
|
|||
|
><I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>Iteration</I
|
|||
|
>:
|
|||
|
Repeated execution of a command or group of commands, usually --
|
|||
|
but not always, <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>while</I
|
|||
|
> a given condition
|
|||
|
holds, or <I
|
|||
|
CLASS="FIRSTTERM"
|
|||
|
>until</I
|
|||
|
> a given condition is
|
|||
|
met.</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="loops.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="nestedloops.html"
|
|||
|
ACCESSKEY="N"
|
|||
|
>Next</A
|
|||
|
></TD
|
|||
|
></TR
|
|||
|
><TR
|
|||
|
><TD
|
|||
|
WIDTH="33%"
|
|||
|
ALIGN="left"
|
|||
|
VALIGN="top"
|
|||
|
>Loops and Branches</TD
|
|||
|
><TD
|
|||
|
WIDTH="34%"
|
|||
|
ALIGN="center"
|
|||
|
VALIGN="top"
|
|||
|
><A
|
|||
|
HREF="loops.html"
|
|||
|
ACCESSKEY="U"
|
|||
|
>Up</A
|
|||
|
></TD
|
|||
|
><TD
|
|||
|
WIDTH="33%"
|
|||
|
ALIGN="right"
|
|||
|
VALIGN="top"
|
|||
|
>Nested Loops</TD
|
|||
|
></TR
|
|||
|
></TABLE
|
|||
|
></DIV
|
|||
|
></BODY
|
|||
|
></HTML
|
|||
|
>
|