shell教程
OutOfMemory.CN技术专栏-> shell-> shell教程-> 9.5. 变量间接引用

9.5. 变量间接引用

假设一个变量的值是第二个变量的名字.这样要如何才能从第一个变量处重新获得第二个变量的值?例如,a=letter_of_alphabet和letter_of_alphabet=z,是否能由a引用得到z?这确实可以办到,这种技术被称为间接引用.它使用不平常的evalvar1=\$$var2序列.例子9-22.间接引用#!/bin/bash#ind-ref.sh:间接变量引用.#访问一个变量内容所指的变

假设一个变量的值是第二个变量的名字. 这样要如何才能从第一个变量处重新获得第二个变量的值?例如,a=letter_of_alphabetletter_of_alphabet=z, 是否能由a引用得到z ? 这确实可以办到,这种技术被称为间接引用.它使用不平常的eval var1=\$$var2 序列.


例子 9-22. 间接引用

#!/bin/bash
# ind-ref.sh: 间接变量引用.
# 访问一个变量内容所指的变量的值.

a=letter_of_alphabet   # 变量"a"保存着另外一个变量的名字.
letter_of_alphabet=z

echo

# 直接引用.
echo "a = $a"          # a = letter_of_alphabet

# 间接引用.
eval a=\$$a
echo "Now a = $a"      # 现在 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
# 在这个简单的情况下,下面的也可以工作吗?(为什么?).
#         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"带着两个参数:"echo"和"\$$t"(相当于 $table_cell_3)

echo

# (多谢Stephane Chazelas解释了上面的语句的现象)


# 另外一个办法是使用${!t}符号,这个在"Bash, 版本 2"章节中讨论.
# 参考脚本 ex78.sh.

exit 0

变量间接引用的实际用处是什么? 它提供了Bash具有C中一点指针的功能,例如,在表格查找中的用处,另外它也有其他一些有趣的应用. . . .

Nils Radtke展示了如何建立动态变量名和求它们的值。当source配置文件时这个技巧很有用。

#!/bin/bash


# ---------------------------------------------
# 这个文件可被另外单独的文件用source命令执行.
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

# ================================================================

#  可以做的更好.

#  注意下面的片断给出了变量getSparc,
#+ 但没有变量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
               # 真

chkMirrorArchs Ia64
echo $?        # 1
               # 假

# 注意:
# -----
# 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" . . .


例子 9-23. 传递一个间接引用给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=2
E_WRONGARGS=65

if [ $# -ne "$ARGS" ] # Check for proper no. of command line args.
then
   echo "Usage: `basename $0` filename column-number"
   exit $E_WRONGARGS
fi

filename=$1
column_number=$2

#===== 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"
# ------------------------------------------------
# End awk script.

#  Indirect variable reference avoids the hassles
#+ of referencing a shell variable within the embedded awk script.
#  Thanks, Stephane Chazelas.


exit 0

间接引用的方法是个小窍门。如果第二个变量更改了它的值,第一个变量必须适当地解除引用(就像上面的例子一样)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). 幸运地是在bash(参考例子。。。)版本2中介绍的${!variable}符号能使间接引用更智能一些。 notation introduced with version 2 of Bash (see Example 34-2) makes indirect referencing more intuitive.

© 内存溢出 OutOfMemory.CN