600 lines
10 KiB
HTML
600 lines
10 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
<HTML
|
|
><HEAD
|
|
><TITLE
|
|
>Indirect References</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="Advanced Topics"
|
|
HREF="part5.html"><LINK
|
|
REL="PREVIOUS"
|
|
TITLE="Arrays"
|
|
HREF="arrays.html"><LINK
|
|
REL="NEXT"
|
|
TITLE="/dev and /proc"
|
|
HREF="devproc.html"></HEAD
|
|
><BODY
|
|
CLASS="CHAPTER"
|
|
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="arrays.html"
|
|
ACCESSKEY="P"
|
|
>Prev</A
|
|
></TD
|
|
><TD
|
|
WIDTH="80%"
|
|
ALIGN="center"
|
|
VALIGN="bottom"
|
|
></TD
|
|
><TD
|
|
WIDTH="10%"
|
|
ALIGN="right"
|
|
VALIGN="bottom"
|
|
><A
|
|
HREF="devproc.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><HR
|
|
ALIGN="LEFT"
|
|
WIDTH="100%"></DIV
|
|
><DIV
|
|
CLASS="CHAPTER"
|
|
><H1
|
|
><A
|
|
NAME="IVR"
|
|
></A
|
|
>Chapter 28. Indirect References</H1
|
|
><P
|
|
><A
|
|
NAME="IVRREF"
|
|
></A
|
|
></P
|
|
><P
|
|
>We have seen that <A
|
|
HREF="varsubn.html"
|
|
>referencing
|
|
a variable</A
|
|
>, <TT
|
|
CLASS="VARNAME"
|
|
>$var</TT
|
|
>, fetches its
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>value</I
|
|
>. <A
|
|
NAME="EVALINDREF"
|
|
></A
|
|
>But,
|
|
what about the <EM
|
|
>value of a value</EM
|
|
>? What
|
|
about <TT
|
|
CLASS="VARNAME"
|
|
>$$var</TT
|
|
>?</P
|
|
><P
|
|
>The actual notation is
|
|
<TT
|
|
CLASS="REPLACEABLE"
|
|
><I
|
|
>\$$var</I
|
|
></TT
|
|
>, usually preceded by
|
|
an <A
|
|
HREF="internal.html#EVALREF"
|
|
>eval</A
|
|
> (and sometimes an
|
|
<A
|
|
HREF="internal.html#ECHOREF"
|
|
>echo</A
|
|
>). This is called an
|
|
<I
|
|
CLASS="FIRSTTERM"
|
|
>indirect reference</I
|
|
>.</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="INDREF"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 28-1. Indirect Variable References</B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
# ind-ref.sh: Indirect variable referencing.
|
|
# Accessing the contents of the contents of a variable.
|
|
|
|
# First, let's fool around a little.
|
|
|
|
var=23
|
|
|
|
echo "\$var = $var" # $var = 23
|
|
# So far, everything as expected. But ...
|
|
|
|
echo "\$\$var = $$var" # $$var = 4570var
|
|
# Not useful ...
|
|
# \$\$ expanded to PID of the script
|
|
# -- refer to the entry on the $$ variable --
|
|
#+ and "var" is echoed as plain text.
|
|
# (Thank you, Jakob Bohm, for pointing this out.)
|
|
|
|
echo "\\\$\$var = \$$var" # \$$var = $23
|
|
# As expected. The first $ is escaped and pasted on to
|
|
#+ the value of var ($var = 23 ).
|
|
# Meaningful, but still not useful.
|
|
|
|
# Now, let's start over and do it the right way.
|
|
|
|
# ============================================== #
|
|
|
|
|
|
a=letter_of_alphabet # Variable "a" holds the name of another variable.
|
|
letter_of_alphabet=z
|
|
|
|
echo
|
|
|
|
# Direct reference.
|
|
echo "a = $a" # a = letter_of_alphabet
|
|
|
|
# Indirect reference.
|
|
eval a=\$$a
|
|
# ^^^ Forcing an eval(uation), and ...
|
|
# ^ Escaping the first $ ...
|
|
# ------------------------------------------------------------------------
|
|
# The 'eval' forces an update of $a, sets it to the updated value of \$$a.
|
|
# So, we see why 'eval' so often shows up in indirect reference notation.
|
|
# ------------------------------------------------------------------------
|
|
echo "Now a = $a" # Now a = z
|
|
|
|
echo
|
|
|
|
|
|
# Now, let's try changing the second-order reference.
|
|
|
|
t=table_cell_3
|
|
table_cell_3=24
|
|
echo "\"table_cell_3\" = $table_cell_3" # "table_cell_3" = 24
|
|
echo -n "dereferenced \"t\" = "; eval echo \$$t # dereferenced "t" = 24
|
|
# In this simple case, the following also works (why?).
|
|
# eval t=\$$t; echo "\"t\" = $t"
|
|
|
|
echo
|
|
|
|
t=table_cell_3
|
|
NEW_VAL=387
|
|
table_cell_3=$NEW_VAL
|
|
echo "Changing value of \"table_cell_3\" to $NEW_VAL."
|
|
echo "\"table_cell_3\" now $table_cell_3"
|
|
echo -n "dereferenced \"t\" now "; eval echo \$$t
|
|
# "eval" takes the two arguments "echo" and "\$$t" (set equal to $table_cell_3)
|
|
|
|
|
|
echo
|
|
|
|
# (Thanks, Stephane Chazelas, for clearing up the above behavior.)
|
|
|
|
|
|
# A more straightforward method is the ${!t} notation, discussed in the
|
|
#+ "Bash, version 2" section.
|
|
# See also ex78.sh.
|
|
|
|
exit 0</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><P
|
|
><A
|
|
NAME="IRRREF"
|
|
></A
|
|
></P
|
|
><TABLE
|
|
CLASS="SIDEBAR"
|
|
BORDER="1"
|
|
CELLPADDING="5"
|
|
><TR
|
|
><TD
|
|
><DIV
|
|
CLASS="SIDEBAR"
|
|
><A
|
|
NAME="AEN18998"
|
|
></A
|
|
><P
|
|
></P
|
|
><P
|
|
>Indirect referencing in Bash
|
|
is a multi-step process. First, take the name of a variable:
|
|
<TT
|
|
CLASS="VARNAME"
|
|
>varname</TT
|
|
>. Then, reference it:
|
|
<TT
|
|
CLASS="VARNAME"
|
|
>$varname</TT
|
|
>. Then, reference the reference:
|
|
<TT
|
|
CLASS="VARNAME"
|
|
>$$varname</TT
|
|
>. Then, <I
|
|
CLASS="FIRSTTERM"
|
|
>escape</I
|
|
>
|
|
the first <SPAN
|
|
CLASS="TOKEN"
|
|
>$</SPAN
|
|
>: <TT
|
|
CLASS="VARNAME"
|
|
>\$$varname</TT
|
|
>.
|
|
Finally, force a reevaluation of the expression and assign it:
|
|
<B
|
|
CLASS="COMMAND"
|
|
>eval newvar=\$$varname</B
|
|
>.</P
|
|
><P
|
|
></P
|
|
></DIV
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
><P
|
|
>Of what practical use is indirect referencing of
|
|
variables? It gives Bash a little of the functionality
|
|
of <A
|
|
HREF="varsubn.html#POINTERREF"
|
|
>pointers</A
|
|
>
|
|
in <I
|
|
CLASS="FIRSTTERM"
|
|
>C</I
|
|
>, for instance, in <A
|
|
HREF="bashver2.html#RESISTOR"
|
|
>table lookup</A
|
|
>. And, it also has some
|
|
other very interesting applications. . . .</P
|
|
><P
|
|
>Nils Radtke shows how to build <SPAN
|
|
CLASS="QUOTE"
|
|
>"dynamic"</SPAN
|
|
>
|
|
variable names and evaluate their contents. This can be useful
|
|
when <A
|
|
HREF="internal.html#SOURCEREF"
|
|
>sourcing</A
|
|
> configuration
|
|
files.</P
|
|
><P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
|
|
|
|
# ---------------------------------------------
|
|
# This could be "sourced" from a separate file.
|
|
isdnMyProviderRemoteNet=172.16.0.100
|
|
isdnYourProviderRemoteNet=10.0.0.10
|
|
isdnOnlineService="MyProvider"
|
|
# ---------------------------------------------
|
|
|
|
|
|
remoteNet=$(eval "echo \$$(echo isdn${isdnOnlineService}RemoteNet)")
|
|
remoteNet=$(eval "echo \$$(echo isdnMyProviderRemoteNet)")
|
|
remoteNet=$(eval "echo \$isdnMyProviderRemoteNet")
|
|
remoteNet=$(eval "echo $isdnMyProviderRemoteNet")
|
|
|
|
echo "$remoteNet" # 172.16.0.100
|
|
|
|
# ================================================================
|
|
|
|
# And, it gets even better.
|
|
|
|
# Consider the following snippet given a variable named getSparc,
|
|
#+ but no such variable getIa64:
|
|
|
|
chkMirrorArchs () {
|
|
arch="$1";
|
|
if [ "$(eval "echo \${$(echo get$(echo -ne $arch |
|
|
sed 's/^\(.\).*/\1/g' | tr 'a-z' 'A-Z'; echo $arch |
|
|
sed 's/^.\(.*\)/\1/g')):-false}")" = true ]
|
|
then
|
|
return 0;
|
|
else
|
|
return 1;
|
|
fi;
|
|
}
|
|
|
|
getSparc="true"
|
|
unset getIa64
|
|
chkMirrorArchs sparc
|
|
echo $? # 0
|
|
# True
|
|
|
|
chkMirrorArchs Ia64
|
|
echo $? # 1
|
|
# False
|
|
|
|
# Notes:
|
|
# -----
|
|
# Even the to-be-substituted variable name part is built explicitly.
|
|
# The parameters to the chkMirrorArchs calls are all lower case.
|
|
# The variable name is composed of two parts: "get" and "Sparc" . . .</PRE
|
|
></FONT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
>
|
|
</P
|
|
><DIV
|
|
CLASS="EXAMPLE"
|
|
><A
|
|
NAME="COLTOTALER2"
|
|
></A
|
|
><P
|
|
><B
|
|
>Example 28-2. Passing an indirect reference to <I
|
|
CLASS="FIRSTTERM"
|
|
>awk</I
|
|
></B
|
|
></P
|
|
><TABLE
|
|
BORDER="0"
|
|
BGCOLOR="#E0E0E0"
|
|
WIDTH="100%"
|
|
><TR
|
|
><TD
|
|
><FONT
|
|
COLOR="#000000"
|
|
><PRE
|
|
CLASS="PROGRAMLISTING"
|
|
>#!/bin/bash
|
|
|
|
# Another version of the "column totaler" script
|
|
#+ that adds up a specified column (of numbers) in the target file.
|
|
# This one uses indirect references.
|
|
|
|
ARGS=2
|
|
E_WRONGARGS=85
|
|
|
|
if [ $# -ne "$ARGS" ] # Check for proper number of command-line args.
|
|
then
|
|
echo "Usage: `basename $0` filename column-number"
|
|
exit $E_WRONGARGS
|
|
fi
|
|
|
|
filename=$1 # Name of file to operate on.
|
|
column_number=$2 # Which column to total up.
|
|
|
|
#===== Same as original script, up to this point =====#
|
|
|
|
|
|
# A multi-line awk script is invoked by
|
|
# awk "
|
|
# ...
|
|
# ...
|
|
# ...
|
|
# "
|
|
|
|
|
|
# Begin awk script.
|
|
# -------------------------------------------------
|
|
awk "
|
|
|
|
{ total += \$${column_number} # Indirect reference
|
|
}
|
|
END {
|
|
print total
|
|
}
|
|
|
|
" "$filename"
|
|
# Note that awk doesn't need an eval preceding \$$.
|
|
# -------------------------------------------------
|
|
# End awk script.
|
|
|
|
# Indirect variable reference avoids the hassles
|
|
#+ of referencing a shell variable within the embedded awk script.
|
|
# Thanks, Stephane Chazelas.
|
|
|
|
|
|
exit $?</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
|
|
>This method of indirect referencing is a bit tricky.
|
|
If the second order variable changes its value, then the first
|
|
order variable must be properly dereferenced (as in the above
|
|
example). <A
|
|
NAME="IVR2"
|
|
></A
|
|
>Fortunately, the
|
|
<TT
|
|
CLASS="REPLACEABLE"
|
|
><I
|
|
>${!variable}</I
|
|
></TT
|
|
> notation introduced
|
|
with <A
|
|
HREF="bashver2.html#BASH2REF"
|
|
>version 2</A
|
|
> of Bash
|
|
(see <A
|
|
HREF="bashver2.html#EX78"
|
|
>Example 37-2</A
|
|
> and <A
|
|
HREF="contributed-scripts.html#HASHEX2"
|
|
>Example A-22</A
|
|
>) makes
|
|
indirect referencing more intuitive.</P
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
><TABLE
|
|
CLASS="SIDEBAR"
|
|
BORDER="1"
|
|
CELLPADDING="5"
|
|
><TR
|
|
><TD
|
|
><DIV
|
|
CLASS="SIDEBAR"
|
|
><A
|
|
NAME="AEN19027"
|
|
></A
|
|
><P
|
|
></P
|
|
><P
|
|
>Bash does not support pointer arithmetic, and this severely
|
|
limits the usefulness of indirect referencing. In fact, indirect
|
|
referencing in a scripting language is, at best, something of
|
|
an afterthought.</P
|
|
><P
|
|
></P
|
|
></DIV
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></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="arrays.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="devproc.html"
|
|
ACCESSKEY="N"
|
|
>Next</A
|
|
></TD
|
|
></TR
|
|
><TR
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="left"
|
|
VALIGN="top"
|
|
>Arrays</TD
|
|
><TD
|
|
WIDTH="34%"
|
|
ALIGN="center"
|
|
VALIGN="top"
|
|
><A
|
|
HREF="part5.html"
|
|
ACCESSKEY="U"
|
|
>Up</A
|
|
></TD
|
|
><TD
|
|
WIDTH="33%"
|
|
ALIGN="right"
|
|
VALIGN="top"
|
|
><TT
|
|
CLASS="FILENAME"
|
|
>/dev</TT
|
|
> and <TT
|
|
CLASS="FILENAME"
|
|
>/proc</TT
|
|
></TD
|
|
></TR
|
|
></TABLE
|
|
></DIV
|
|
></BODY
|
|
></HTML
|
|
> |