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

1432 lines
24 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML
><HEAD
><TITLE
>Complex Functions and Function Complexities</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="Functions"
HREF="functions.html"><LINK
REL="PREVIOUS"
TITLE="Functions"
HREF="functions.html"><LINK
REL="NEXT"
TITLE="Local Variables"
HREF="localvar.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="functions.html"
ACCESSKEY="P"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 24. Functions</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="localvar.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="COMPLEXFUNCT"
></A
>24.1. Complex Functions and Function Complexities</H1
><P
>Functions may process arguments passed to them and return
an <A
HREF="exit-status.html#EXITSTATUSREF"
>exit status</A
> to the script
for further processing.</P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>function_name $arg1 $arg2</PRE
></FONT
></TD
></TR
></TABLE
><P
><A
NAME="PASSEDARGS"
></A
></P
><P
>The function refers to the passed arguments by position (as if they were
<A
HREF="internalvariables.html#POSPARAMREF"
>positional parameters</A
>),
that is, <TT
CLASS="VARNAME"
>$1</TT
>, <TT
CLASS="VARNAME"
>$2</TT
>, and
so forth.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="EX60"
></A
><P
><B
>Example 24-2. Function Taking Parameters</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# Functions and parameters
DEFAULT=default # Default param value.
func2 () {
if [ -z "$1" ] # Is parameter #1 zero length?
then
echo "-Parameter #1 is zero length.-" # Or no parameter passed.
else
echo "-Parameter #1 is \"$1\".-"
fi
variable=${1-$DEFAULT} # What does
echo "variable = $variable" #+ parameter substitution show?
# ---------------------------
# It distinguishes between
#+ no param and a null param.
if [ "$2" ]
then
echo "-Parameter #2 is \"$2\".-"
fi
return 0
}
echo
echo "Nothing passed."
func2 # Called with no params
echo
echo "Zero-length parameter passed."
func2 "" # Called with zero-length param
echo
echo "Null parameter passed."
func2 "$uninitialized_param" # Called with uninitialized param
echo
echo "One parameter passed."
func2 first # Called with one param
echo
echo "Two parameters passed."
func2 first second # Called with two params
echo
echo "\"\" \"second\" passed."
func2 "" second # Called with zero-length first parameter
echo # and ASCII string as a second one.
exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
><A
NAME="FSHIFTREF"
></A
></P
><DIV
CLASS="IMPORTANT"
><P
></P
><TABLE
CLASS="IMPORTANT"
WIDTH="100%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/important.gif"
HSPACE="5"
ALT="Important"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>The <A
HREF="othertypesv.html#SHIFTREF"
>shift</A
>
command works on arguments passed to functions (see <A
HREF="assortedtips.html#MULTIPLICATION"
>Example 36-18</A
>).</P
></TD
></TR
></TABLE
></DIV
><P
>But, what about command-line arguments passed to the script?
Does a function see them? Well, let's clear up the confusion.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="FUNCCMDLINEARG"
></A
><P
><B
>Example 24-3. Functions and command-line args passed to the script</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# func-cmdlinearg.sh
# Call this script with a command-line argument,
#+ something like $0 arg1.
func ()
{
echo "$1" # Echoes first arg passed to the function.
} # Does a command-line arg qualify?
echo "First call to function: no arg passed."
echo "See if command-line arg is seen."
func
# No! Command-line arg not seen.
echo "============================================================"
echo
echo "Second call to function: command-line arg passed explicitly."
func $1
# Now it's seen!
exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>In contrast to certain other programming languages,
shell scripts normally pass only value parameters to
functions. Variable names (which are actually
<I
CLASS="FIRSTTERM"
>pointers</I
>), if
passed as parameters to functions, will be treated as string
literals. <EM
>Functions interpret their arguments
literally.</EM
></P
><P
><A
NAME="FUNCPOINTERS"
></A
></P
><P
><A
HREF="ivr.html#IVRREF"
>Indirect variable
references</A
> (see <A
HREF="bashver2.html#EX78"
>Example 37-2</A
>) provide a clumsy
sort of mechanism for passing variable pointers to
functions.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="INDFUNC"
></A
><P
><B
>Example 24-4. Passing an indirect reference to a function</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# ind-func.sh: Passing an indirect reference to a function.
echo_var ()
{
echo "$1"
}
message=Hello
Hello=Goodbye
echo_var "$message" # Hello
# Now, let's pass an indirect reference to the function.
echo_var "${!message}" # Goodbye
echo "-------------"
# What happens if we change the contents of "hello" variable?
Hello="Hello, again!"
echo_var "$message" # Hello
echo_var "${!message}" # Hello, again!
exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>The next logical question is whether parameters can be
dereferenced <EM
>after</EM
> being passed to a
function.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="DEREFERENCECL"
></A
><P
><B
>Example 24-5. Dereferencing a parameter passed to a function</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# dereference.sh
# Dereferencing parameter passed to a function.
# Script by Bruce W. Clare.
dereference ()
{
y=\$"$1" # Name of variable (not value!).
echo $y # $Junk
x=`eval "expr \"$y\" "`
echo $1=$x
eval "$1=\"Some Different Text \"" # Assign new value.
}
Junk="Some Text"
echo $Junk "before" # Some Text before
dereference Junk
echo $Junk "after" # Some Different Text after
exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="REFPARAMS"
></A
><P
><B
>Example 24-6. Again, dereferencing a parameter passed to a function</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# ref-params.sh: Dereferencing a parameter passed to a function.
# (Complex Example)
ITERATIONS=3 # How many times to get input.
icount=1
my_read () {
# Called with my_read varname,
#+ outputs the previous value between brackets as the default value,
#+ then asks for a new value.
local local_var
echo -n "Enter a value "
eval 'echo -n "[$'$1'] "' # Previous value.
# eval echo -n "[\$$1] " # Easier to understand,
#+ but loses trailing space in user prompt.
read local_var
[ -n "$local_var" ] &#38;&#38; eval $1=\$local_var
# "And-list": if "local_var" then set "$1" to its value.
}
echo
while [ "$icount" -le "$ITERATIONS" ]
do
my_read var
echo "Entry #$icount = $var"
let "icount += 1"
echo
done
# Thanks to Stephane Chazelas for providing this instructive example.
exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
></P
><DIV
CLASS="VARIABLELIST"
><P
><B
><A
NAME="EXITRETURN1"
></A
>Exit and Return</B
></P
><DL
><DT
><B
CLASS="COMMAND"
>exit status</B
></DT
><DD
><P
>Functions return a value, called an <I
CLASS="FIRSTTERM"
>exit
status</I
>. This is analogous to the <A
HREF="exit-status.html#EXITSTATUSREF"
>exit status</A
> returned by a
command. The exit status may be explicitly specified
by a <B
CLASS="COMMAND"
>return</B
> statement, otherwise it
is the exit status of the last command in the function
(<SPAN
CLASS="RETURNVALUE"
>0</SPAN
> if successful, and a non-zero
error code if not). This <A
HREF="exit-status.html#EXITSTATUSREF"
>exit
status</A
> may be used in the script by referencing it
as <A
HREF="internalvariables.html#XSTATVARREF"
>$?</A
>. This mechanism
effectively permits script functions to have a <SPAN
CLASS="QUOTE"
>"return
value"</SPAN
> similar to C functions.</P
></DD
><DT
><B
CLASS="COMMAND"
>return</B
></DT
><DD
><P
><A
NAME="RETURNREF"
></A
></P
><P
>Terminates a function. A <B
CLASS="COMMAND"
>return</B
> command
<A
NAME="AEN18474"
HREF="#FTN.AEN18474"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
>
optionally takes an <I
CLASS="FIRSTTERM"
>integer</I
>
argument, which is returned to the calling script as
the <SPAN
CLASS="QUOTE"
>"exit status"</SPAN
> of the function, and
this exit status is assigned to the variable <A
HREF="internalvariables.html#XSTATVARREF"
>$?</A
>.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="MAX"
></A
><P
><B
>Example 24-7. Maximum of two numbers</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# max.sh: Maximum of two integers.
E_PARAM_ERR=250 # If less than 2 params passed to function.
EQUAL=251 # Return value if both params equal.
# Error values out of range of any
#+ params that might be fed to the function.
max2 () # Returns larger of two numbers.
{ # Note: numbers compared must be less than 250.
if [ -z "$2" ]
then
return $E_PARAM_ERR
fi
if [ "$1" -eq "$2" ]
then
return $EQUAL
else
if [ "$1" -gt "$2" ]
then
return $1
else
return $2
fi
fi
}
max2 33 34
return_val=$?
if [ "$return_val" -eq $E_PARAM_ERR ]
then
echo "Need to pass two parameters to the function."
elif [ "$return_val" -eq $EQUAL ]
then
echo "The two numbers are equal."
else
echo "The larger of the two numbers is $return_val."
fi
exit 0
# Exercise (easy):
# ---------------
# Convert this to an interactive script,
#+ that is, have the script ask for input (two numbers).</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="TIP"
><P
></P
><TABLE
CLASS="TIP"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/tip.gif"
HSPACE="5"
ALT="Tip"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>For a function to return a string or array, use a
dedicated variable.
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>count_lines_in_etc_passwd()
{
[[ -r /etc/passwd ]] &#38;&#38; REPLY=$(echo $(wc -l &#60; /etc/passwd))
# If /etc/passwd is readable, set REPLY to line count.
# Returns both a parameter value and status information.
# The 'echo' seems unnecessary, but . . .
#+ it removes excess whitespace from the output.
}
if count_lines_in_etc_passwd
then
echo "There are $REPLY lines in /etc/passwd."
else
echo "Cannot count lines in /etc/passwd."
fi
# Thanks, S.C.</PRE
></FONT
></TD
></TR
></TABLE
>
</P
></TD
></TR
></TABLE
></DIV
><DIV
CLASS="EXAMPLE"
><A
NAME="EX61"
></A
><P
><B
>Example 24-8. Converting numbers to Roman numerals</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# Arabic number to Roman numeral conversion
# Range: 0 - 200
# It's crude, but it works.
# Extending the range and otherwise improving the script is left as an exercise.
# Usage: roman number-to-convert
LIMIT=200
E_ARG_ERR=65
E_OUT_OF_RANGE=66
if [ -z "$1" ]
then
echo "Usage: `basename $0` number-to-convert"
exit $E_ARG_ERR
fi
num=$1
if [ "$num" -gt $LIMIT ]
then
echo "Out of range!"
exit $E_OUT_OF_RANGE
fi
to_roman () # Must declare function before first call to it.
{
number=$1
factor=$2
rchar=$3
let "remainder = number - factor"
while [ "$remainder" -ge 0 ]
do
echo -n $rchar
let "number -= factor"
let "remainder = number - factor"
done
return $number
# Exercises:
# ---------
# 1) Explain how this function works.
# Hint: division by successive subtraction.
# 2) Extend to range of the function.
# Hint: use "echo" and command-substitution capture.
}
to_roman $num 100 C
num=$?
to_roman $num 90 LXXXX
num=$?
to_roman $num 50 L
num=$?
to_roman $num 40 XL
num=$?
to_roman $num 10 X
num=$?
to_roman $num 9 IX
num=$?
to_roman $num 5 V
num=$?
to_roman $num 4 IV
num=$?
to_roman $num 1 I
# Successive calls to conversion function!
# Is this really necessary??? Can it be simplified?
echo
exit</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>See also <A
HREF="testbranch.html#ISALPHA"
>Example 11-29</A
>.</P
><DIV
CLASS="IMPORTANT"
><P
></P
><TABLE
CLASS="IMPORTANT"
WIDTH="90%"
BORDER="0"
><TR
><TD
WIDTH="25"
ALIGN="CENTER"
VALIGN="TOP"
><IMG
SRC="../images/important.gif"
HSPACE="5"
ALT="Important"></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
><P
>The largest positive integer a function can return is
255. The <B
CLASS="COMMAND"
>return</B
> command is closely tied
to the concept of <A
HREF="exit-status.html#EXITSTATUSREF"
>exit
status</A
>, which accounts for this particular
limitation. Fortunately, there are various <A
HREF="assortedtips.html#RVT"
>workarounds</A
> for those situations
requiring a large integer return value from a
function.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="RETURNTEST"
></A
><P
><B
>Example 24-9. Testing large return values in a function</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# return-test.sh
# The largest positive value a function can return is 255.
return_test () # Returns whatever passed to it.
{
return $1
}
return_test 27 # o.k.
echo $? # Returns 27.
return_test 255 # Still o.k.
echo $? # Returns 255.
return_test 257 # Error!
echo $? # Returns 1 (return code for miscellaneous error).
# =========================================================
return_test -151896 # Do large negative numbers work?
echo $? # Will this return -151896?
# No! It returns 168.
# Version of Bash before 2.05b permitted
#+ large negative integer return values.
# It happened to be a useful feature.
# Newer versions of Bash unfortunately plug this loophole.
# This may break older scripts.
# Caution!
# =========================================================
exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>A workaround for obtaining large integer <SPAN
CLASS="QUOTE"
>"return
values"</SPAN
> is to simply assign the <SPAN
CLASS="QUOTE"
>"return
value"</SPAN
> to a global variable.
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>Return_Val= # Global variable to hold oversize return value of function.
alt_return_test ()
{
fvar=$1
Return_Val=$fvar
return # Returns 0 (success).
}
alt_return_test 1
echo $? # 0
echo "return value = $Return_Val" # 1
alt_return_test 256
echo "return value = $Return_Val" # 256
alt_return_test 257
echo "return value = $Return_Val" # 257
alt_return_test 25701
echo "return value = $Return_Val" #25701</PRE
></FONT
></TD
></TR
></TABLE
>
</P
><P
><A
NAME="CAPTURERETVAL"
></A
></P
><P
>A more elegant method is to have the function
<B
CLASS="COMMAND"
>echo</B
> its <SPAN
CLASS="QUOTE"
>"return
value to <TT
CLASS="FILENAME"
>stdout</TT
>,"</SPAN
> and
then capture it by <A
HREF="commandsub.html#COMMANDSUBREF"
>command
substitution</A
>. See the <A
HREF="assortedtips.html#RVT"
>discussion
of this</A
> in <A
HREF="assortedtips.html"
>Section 36.7</A
>.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="MAX2"
></A
><P
><B
>Example 24-10. Comparing two large integers</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# max2.sh: Maximum of two LARGE integers.
# This is the previous "max.sh" example,
#+ modified to permit comparing large integers.
EQUAL=0 # Return value if both params equal.
E_PARAM_ERR=-99999 # Not enough params passed to function.
# ^^^^^^ Out of range of any params that might be passed.
max2 () # "Returns" larger of two numbers.
{
if [ -z "$2" ]
then
echo $E_PARAM_ERR
return
fi
if [ "$1" -eq "$2" ]
then
echo $EQUAL
return
else
if [ "$1" -gt "$2" ]
then
retval=$1
else
retval=$2
fi
fi
echo $retval # Echoes (to stdout), rather than returning value.
# Why?
}
return_val=$(max2 33001 33997)
# ^^^^ Function name
# ^^^^^ ^^^^^ Params passed
# This is actually a form of command substitution:
#+ treating a function as if it were a command,
#+ and assigning the stdout of the function to the variable "return_val."
# ========================= OUTPUT ========================
if [ "$return_val" -eq "$E_PARAM_ERR" ]
then
echo "Error in parameters passed to comparison function!"
elif [ "$return_val" -eq "$EQUAL" ]
then
echo "The two numbers are equal."
else
echo "The larger of the two numbers is $return_val."
fi
# =========================================================
exit 0
# Exercises:
# ---------
# 1) Find a more elegant way of testing
#+ the parameters passed to the function.
# 2) Simplify the if/then structure at "OUTPUT."
# 3) Rewrite the script to take input from command-line parameters.</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>Here is another example of capturing a function
<SPAN
CLASS="QUOTE"
>"return value."</SPAN
> Understanding it requires some
knowledge of <A
HREF="awk.html#AWKREF"
>awk</A
>.
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>month_length () # Takes month number as an argument.
{ # Returns number of days in month.
monthD="31 28 31 30 31 30 31 31 30 31 30 31" # Declare as local?
echo "$monthD" | awk '{ print $'"${1}"' }' # Tricky.
# ^^^^^^^^^
# Parameter passed to function ($1 -- month number), then to awk.
# Awk sees this as "print $1 . . . print $12" (depending on month number)
# Template for passing a parameter to embedded awk script:
# $'"${script_parameter}"'
# Here's a slightly simpler awk construct:
# echo $monthD | awk -v month=$1 '{print $(month)}'
# Uses the -v awk option, which assigns a variable value
#+ prior to execution of the awk program block.
# Thank you, Rich.
# Needs error checking for correct parameter range (1-12)
#+ and for February in leap year.
}
# ----------------------------------------------
# Usage example:
month=4 # April, for example (4th month).
days_in=$(month_length $month)
echo $days_in # 30
# ----------------------------------------------</PRE
></FONT
></TD
></TR
></TABLE
></P
><P
>See also <A
HREF="contributed-scripts.html#DAYSBETWEEN"
>Example A-7</A
>
and <A
HREF="contributed-scripts.html#STDDEV"
>Example A-37</A
>.</P
><P
><TT
CLASS="USERINPUT"
><B
>Exercise:</B
></TT
> Using what we have
just learned, extend the previous <A
HREF="complexfunct.html#EX61"
>Roman numerals example</A
> to accept
arbitrarily large input.</P
></TD
></TR
></TABLE
></DIV
></DD
></DL
></DIV
><P
></P
><DIV
CLASS="VARIABLELIST"
><P
><B
><A
NAME="REDSTDINFUNC1"
></A
>Redirection</B
></P
><DL
><DT
><TT
CLASS="REPLACEABLE"
><I
>Redirecting the stdin
of a function</I
></TT
></DT
><DD
><P
>A function is essentially a <A
HREF="special-chars.html#CODEBLOCKREF"
>code block</A
>, which means its
<TT
CLASS="FILENAME"
>stdin</TT
> can be redirected (as in <A
HREF="special-chars.html#EX8"
>Example 3-1</A
>).</P
><DIV
CLASS="EXAMPLE"
><A
NAME="REALNAME"
></A
><P
><B
>Example 24-11. Real name from username</B
></P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
>#!/bin/bash
# realname.sh
#
# From username, gets "real name" from /etc/passwd.
ARGCOUNT=1 # Expect one arg.
E_WRONGARGS=85
file=/etc/passwd
pattern=$1
if [ $# -ne "$ARGCOUNT" ]
then
echo "Usage: `basename $0` USERNAME"
exit $E_WRONGARGS
fi
file_excerpt () # Scan file for pattern,
{ #+ then print relevant portion of line.
while read line # "while" does not necessarily need [ condition ]
do
echo "$line" | grep $1 | awk -F":" '{ print $5 }'
# Have awk use ":" delimiter.
done
} &#60;$file # Redirect into function's stdin.
file_excerpt $pattern
# Yes, this entire script could be reduced to
# grep PATTERN /etc/passwd | awk -F":" '{ print $5 }'
# or
# awk -F: '/PATTERN/ {print $5}'
# or
# awk -F: '($1 == "username") { print $5 }' # real name from username
# However, it might not be as instructive.
exit 0</PRE
></FONT
></TD
></TR
></TABLE
></DIV
><P
>There is an alternate, and perhaps less confusing
method of redirecting a function's
<TT
CLASS="FILENAME"
>stdin</TT
>. This involves redirecting the
<TT
CLASS="FILENAME"
>stdin</TT
> to an embedded bracketed code
block within the function.
<TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="90%"
><TR
><TD
><FONT
COLOR="#000000"
><PRE
CLASS="PROGRAMLISTING"
># Instead of:
Function ()
{
...
} &#60; file
# Try this:
Function ()
{
{
...
} &#60; file
}
# Similarly,
Function () # This works.
{
{
echo $*
} | tr a b
}
Function () # This doesn't work.
{
echo $*
} | tr a b # A nested code block is mandatory here.
# Thanks, S.C.</PRE
></FONT
></TD
></TR
></TABLE
>
</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
>Emmanuel Rouat's <A
HREF="sample-bashrc.html"
>sample <TT
CLASS="FILENAME"
>bashrc</TT
>
file</A
> contains some instructive examples of
functions.</P
></TD
></TR
></TABLE
></DIV
></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.AEN18474"
HREF="complexfunct.html#AEN18474"
><SPAN
CLASS="footnote"
>[1]</SPAN
></A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
WIDTH="95%"
><P
>The <B
CLASS="COMMAND"
>return</B
> command is a
Bash <A
HREF="internal.html#BUILTINREF"
>builtin</A
>.</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="functions.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="localvar.html"
ACCESSKEY="N"
>Next</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Functions</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="functions.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Local Variables</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>