old-www/LDP/abs/html/recursionsct.html

391 lines
7.5 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML
><HEAD
><TITLE
>Recursion: a script calling itself</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="Miscellany"
HREF="miscellany.html"><LINK
REL="PREVIOUS"
TITLE="Tests and Comparisons: Alternatives"
HREF="testsandcomparisons.html"><LINK
REL="NEXT"
TITLE="Colorizing Scripts"
HREF="colorizing.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="testsandcomparisons.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 36. Miscellany</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="colorizing.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="RECURSIONSCT"
></A
>36.4. Recursion: a script calling itself</H1
><P
><A
NAME="SCRIPTRECURSION"
></A
></P
><P
>Can a script <A
HREF="localvar.html#RECURSIONREF"
>recursively</A
>
call itself? Indeed.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="RECURSE"
></A
><P
><B
>Example 36-10. A (useless) script that recursively calls itself</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# recurse.sh
# Can a script recursively call itself?
# Yes, but is this of any practical use?
# (See the following.)
RANGE=10
MAXVAL=9
i=$RANDOM
let "i %= $RANGE" # Generate a random number between 0 and $RANGE - 1.
if [ "$i" -lt "$MAXVAL" ]
then
echo "i = $i"
./$0 # Script recursively spawns a new instance of itself.
fi # Each child script does the same, until
#+ a generated $i equals $MAXVAL.
# Using a "while" loop instead of an "if/then" test causes problems.
# Explain why.
exit 0
# Note:
# ----
# This script must have execute permission for it to work properly.
# This is the case even if it is invoked by an "sh" command.
# Explain why.</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="PBOOK"
></A
><P
><B
>Example 36-11. A (useful) script that recursively calls itself</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# pb.sh: phone book
# Written by Rick Boivie, and used with permission.
# Modifications by ABS Guide author.
MINARGS=1 # Script needs at least one argument.
DATAFILE=./phonebook
# A data file in current working directory
#+ named "phonebook" must exist.
PROGNAME=$0
E_NOARGS=70 # No arguments error.
if [ $# -lt $MINARGS ]; then
echo "Usage: "$PROGNAME" data-to-look-up"
exit $E_NOARGS
fi
if [ $# -eq $MINARGS ]; then
grep $1 "$DATAFILE"
# 'grep' prints an error message if $DATAFILE not present.
else
( shift; "$PROGNAME" $* ) | grep $1
# Script recursively calls itself.
fi
exit 0 # Script exits here.
# Therefore, it's o.k. to put
#+ non-hashmarked comments and data after this point.
# ------------------------------------------------------------------------
Sample "phonebook" datafile:
John Doe 1555 Main St., Baltimore, MD 21228 (410) 222-3333
Mary Moe 9899 Jones Blvd., Warren, NH 03787 (603) 898-3232
Richard Roe 856 E. 7th St., New York, NY 10009 (212) 333-4567
Sam Roe 956 E. 8th St., New York, NY 10009 (212) 444-5678
Zoe Zenobia 4481 N. Baker St., San Francisco, SF 94338 (415) 501-1631
# ------------------------------------------------------------------------
$bash pb.sh Roe
Richard Roe 856 E. 7th St., New York, NY 10009 (212) 333-4567
Sam Roe 956 E. 8th St., New York, NY 10009 (212) 444-5678
$bash pb.sh Roe Sam
Sam Roe 956 E. 8th St., New York, NY 10009 (212) 444-5678
# When more than one argument is passed to this script,
#+ it prints *only* the line(s) containing all the arguments.</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="USRMNT"
></A
><P
><B
>Example 36-12. Another (useful) script that recursively calls itself</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# usrmnt.sh, written by Anthony Richardson
# Used in ABS Guide with permission.
# usage: usrmnt.sh
# description: mount device, invoking user must be listed in the
# MNTUSERS group in the /etc/sudoers file.
# ----------------------------------------------------------
# This is a usermount script that reruns itself using sudo.
# A user with the proper permissions only has to type
# usermount /dev/fd0 /mnt/floppy
# instead of
# sudo usermount /dev/fd0 /mnt/floppy
# I use this same technique for all of my
#+ sudo scripts, because I find it convenient.
# ----------------------------------------------------------
# If SUDO_COMMAND variable is not set we are not being run through
#+ sudo, so rerun ourselves. Pass the user's real and group id . . .
if [ -z "$SUDO_COMMAND" ]
then
mntusr=$(id -u) grpusr=$(id -g) sudo $0 $*
exit 0
fi
# We will only get here if we are being run by sudo.
/bin/mount $* -o uid=$mntusr,gid=$grpusr
exit 0
# Additional notes (from the author of this script):
# -------------------------------------------------
# 1) Linux allows the "users" option in the /etc/fstab
# file so that any user can mount removable media.
# But, on a server, I like to allow only a few
# individuals access to removable media.
# I find using sudo gives me more control.
# 2) I also find sudo to be more convenient than
# accomplishing this task through groups.
# 3) This method gives anyone with proper permissions
# root access to the mount command, so be careful
# about who you allow access.
# You can get finer control over which access can be mounted
# by using this same technique in separate mntfloppy, mntcdrom,
# and mntsamba scripts.</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="CAUTION"
><P
></P
><TABLE
CLASS="CAUTION"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/caution.gif"
HSPACE="5"
ALT="Caution"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>Too many levels of recursion can exhaust the
script's stack space, causing a segfault.</P
></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="testsandcomparisons.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="colorizing.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Tests and Comparisons: Alternatives</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="miscellany.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
><SPAN
CLASS="QUOTE"
>"Colorizing"</SPAN
> Scripts</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>