从https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
参数展开的基本形式是
${parameter}
。 ...如果参数的第一个字符是感叹号 (
!
),则引入一级变量间接寻址。 Bash 使用由参数的其余部分形成的变量的值作为变量的名称;然后扩展该变量,并在其余替换中使用该值,而不是参数本身的值。这称为间接扩展。例外情况是下面描述的${!prefix}
扩展。${!name[@]}
感叹号必须紧跟在左大括号之后才能引入间接关系。...
${!prefix*} ${!prefix@}
扩展为名称以 prefix 开头的变量名称,由 IFS 特殊变量的第一个字符分隔。当使用“@”并且扩展出现在双引号内时,每个变量名称都会扩展为一个单独的单词。
${!name[@]} ${!name[*]}
如果 name 是数组变量,则扩展到 name 中分配的数组索引(键)列表。如果 name 不是数组,则在设置 name 时扩展为 0,否则扩展为 null。当使用“@”并且扩展出现在双引号内时,每个键都会扩展为一个单独的单词。
您能为引用的段落举一些例子吗?我不知道他们的意思。
答案1
我们需要比较(并区分):
"${Var}" # Plain variable
"${!Var}" # Indirect expansion
"${!Var@}" # Prefix expansion
"${!Var[@]}" # Array keys expansion
"${Var[@]}" # Plain array expansion
还有一些*
非常相似但有细微差别的扩展。
间接
间接示例:
$ varname=var_one
$ var_one=a-value
$ echo "${varname}"
var_one
$ echo "${!varname} and ${var_one}"
a-value and a-value
字首
前缀示例:
$ head_one=foo
$ head_two=bar
$ printf '<%s> ' "${!head@}"
<head_one> <head_two>
$ printf '<%s> ' "${!head*}"
<head_one head_two>
请注意,变量通过 IFS 的第一个字符粘合在一起,默认情况下该字符是空格(就像 IFSSpace Tab NewLine默认情况下一样)。
普通阵列
数组示例(未使用!)显示@
和的微小(但重要)差异*
:
$ Array[1]=This
$ Array[2]=is
$ Array[3]=a
$ Array[4]=simple
$ Array[5]=test.
$ printf '<%s> ' "${Array[@]}"
<This> <is> <a> <simple> <test.>
$ printf '<%s> ' "${Array[*]}"
<This is a simple test.>
关于 IFS 的相同评论也适用于此。
请注意,我没有(故意)分配 Array 的索引 0。
请注意,分配数组的更简单方法是:
$ Array=( "" This is a simple test.)
但这里必须使用索引0,而我使用了一个空值(这与上面未设置的值不同)。
数组列表
为此,一个简单的索引数组(带有数字)就没那么有趣了:
$ Array=( "" A simple example of an array.)
$ printf '<%s> ' "${!Array[@]}"
<0> <1> <2> <3> <4> <5> <6>
$ printf '<%s> ' "${!Array[*]}"
<0 1 2 3 4 5 6>
但对于关联数组,事情变得更有趣
$ unset Array # erase any notion of variable array.
$ declare -A Array # make it associative
$ Array=([foo]=one [bar]=two [baz]=three) # give it values.
$ printf '<%s> ' "${Array[@]}"
<two> <three> <one> # List of values.
$ printf '<%s> ' "${!Array[@]}"
<bar> <baz> <foo> # List of keys
$ printf '<%s> ' "${Array[*]}"
<two three one> # One string of list of values.
$ printf '<%s> ' "${!Array[*]}"
<bar baz foo> # One string of list of keys.
请注意,顺序与分配时不同。
笔记:我提出的所有用法都被引用"${!Array[@]}"
,未引用的值${!Array[@]}
和${!Array[*]}
工作完全相同,给出相同的输出(在 Bash 中)。
但会受到 shell 分裂对 IFS 值的影响。还有丑陋的、总是有问题的“路径名扩展”。一般来说不太有用。或者无论如何都要非常小心地使用。
答案2
看一眼BinaryZebra 的回答以获得详细的解释。以下来自 TLDP 的引用据说是不正确的。
原来的:
看着http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html:
如果“PARAMETER”的第一个字符是感叹号,Bash 使用“PARAMETER”其余部分形成的变量值作为变量的名称;然后扩展该变量,并在其余替换中使用该值,而不是“PARAMETER”本身的值。这称为间接扩展。
您当然熟悉直接参数扩展,因为它一直在发生,即使是在最简单的情况下,例如上面或下面的情况:
franky ~> echo $SHELL /bin/bash
下面是间接扩展的例子:
franky ~> echo ${!N*} NNTPPORT NNTPSERVER NPX_PLUGIN_PATH
请注意,这与 echo 不同
$N*
。
您可以在 shell 中看到它的效果。
例子:
$ TEST=(test1 test2 test3)
$ echo ${!TEST*}
TEST
$ echo ${!TEST[@]}
0 1 2
$ echo ${TEST[@]}
test1 test2 test3
$ echo ${#TEST[@]}
4
${!TEST[@]}
请注意使用、${TEST[@]}
和之间的区别${#TEST[@]}
。