Cari di Shell Script 
    Shell Script Linux Reference Manual
Daftar Isi
(Sebelumnya) 27. Arrays29. /dev and /proc, Playing mu ... (Berikutnya)

Chapter 28. Indirect References

We have seen that referencing a variable, $var, fetches its value. But, what about the value of a value? What about $$var?

The actual notation is$$var, usually preceded byan eval (and sometimes anecho). This is called anindirect reference.

Example 28-1. Indirect Variable References

#!/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=23echo "$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=zecho# 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 = zecho# Now, let's try changing the second-order reference.t=table_cell_3table_cell_3=24echo ""table_cell_3" = $table_cell_3" # "table_cell_3" = 24echo -n "dereferenced "t" = "; eval echo $$t # dereferenced "t" = 24# In this simple case, the following also works (why?).# eval t=$$t; echo ""t" = $t" echot=table_cell_3NEW_VAL=387table_cell_3=$NEW_VALecho "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

Of what practical use is indirect referencing of variables? It gives Bash a little of the functionality of pointers in C, for instance, in table lookup. And, it also has some other very interesting applications. . . .

Nils Radtke shows how to build "dynamic" variable names and evaluate their contents. This can be useful when sourcing configuration files.

#!/bin/bash# ---------------------------------------------# This could be "sourced" from a separate file.isdnMyProviderRemoteNet=172.16.0.100isdnYourProviderRemoteNet=10.0.0.10isdnOnlineService="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 getIa64chkMirrorArchs sparcecho $? # 0   # TruechkMirrorArchs Ia64echo $? # 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" . . .

Example 28-2. Passing an indirect reference to awk

#!/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=2E_WRONGARGS=85if [ $# -ne "$ARGS" ] # Check for proper number of command-line args.then   echo "Usage: `basename $0` filename column-number" exit $E_WRONGARGSfifilename=$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 $?

This method of indirect referencing is a bit tricky.If the second order variable changes its value, then the firstorder variable must be properly dereferenced (as in the aboveexample). Fortunately, the${!variable} notation introducedwith version 2 of Bash(see Example 37-2 and Example A-22) makesindirect referencing more intuitive.


Copyright © 2000, by Mendel Cooper <[email protected]>
(Sebelumnya) 27. Arrays29. /dev and /proc, Playing mu ... (Berikutnya)