的用法!在参数扩展中

Tim*_*Tim 3 bash

来自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。当使用 '@' 并且扩展出现在双引号内时,每个键都扩展为一个单独的词。

你能举一些引用段落的例子吗?我不知道他们的意思。

小智 7

我们需要比较(并区分):

"${Var}"          # Plain variable
"${!Var}"         # Indirect expansion
"${!Var@}"        # Prefix expansion
"${!Var[@]}"      # Array keys expansion
"${Var[@]}"       # Plain array expansion
Run Code Online (Sandbox Code Playgroud)

还有一些*扩展非常相似,但差异很小。

间接

间接示例:

$ varname=var_one
$ var_one=a-value

$ echo "${varname}"
var_one
$ echo "${!varname} and ${var_one}"
a-value and a-value
Run Code Online (Sandbox Code Playgroud)

字首

前缀示例:

$ head_one=foo
$ head_two=bar

$ printf '<%s> ' "${!head@}"
<head_one> <head_two>
$ printf '<%s> ' "${!head*}"
<head_one head_two>
Run Code Online (Sandbox Code Playgroud)

请注意,变量由 IFS 的第一个字符粘合在一起,默认情况下是一个空格(因为默认情况下是 IFS Space 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.>
Run Code Online (Sandbox Code Playgroud)

关于 IFS 的相同评论也适用于此。

请注意,我没有分配 Array 的索引 0(故意)。

请注意,分配数组的更简单方法是:

$ Array=( "" This is a simple test.)
Run Code Online (Sandbox Code Playgroud)

但是这里必须使用索引 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>
Run Code Online (Sandbox Code Playgroud)

但是对于关联数组,事情变得更有趣

$ 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.
Run Code Online (Sandbox Code Playgroud)

请注意,顺序与分配时不同。


注意:我提出的所有用法都是引用的"${!Array[@]}",未引用的值${!Array[@]}${!Array[*]}工作完全相同,给出相同的输出(在 Bash 中)。
但受 IFS 值上的 shell 拆分的影响。还有丑陋的,总是有问题的“路径名扩展”。一般用处不大。或者在任何情况下都必须非常小心地使用。