95

我正在阅读“ Bash 初学者指南”。它说:

如果 of 的第一个字符PARAMETER是感叹号,Bash 使用由其余字符组成的变量的值作为变量PARAMETER的名称;然后扩展此变量,并将该值用于替换的其余部分,而不是其PARAMETER自身的值。这称为间接扩展。

给出的例子是:

franky ~> echo ${!N*}
NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

这里不太明白:

由其余部分形成的变量的值PARAMETER

PARAMETER原样!N*,那么

其余的PARAMETER

只是N*。这怎么可能形成一个变量?Bash 是否在那里搜索了所有可能的命令?

4

6 回答 6

122

如果您阅读bash手册页,它基本上证实了您所说的:

如果参数的第一个字符是感叹号 ( !),则引入了变量间接级别。Bash 使用由其余参数形成的变量的值作为变量的名称;然后扩展此变量,并将该值用于替换的其余部分,而不是参数本身的值。这称为间接扩展。

但是,从那里继续阅读:

例外情况是下面的扩展${!prefix*}${!name[@]}描述。

${!prefix*}名称匹配前缀。扩展为名称以前缀开头的变量的名称,由IFS特殊变量的第一个字符分隔。

换句话说,您的特定示例${!N*}是您引用的规则的例外。但是,它确实像在预期情况下所宣传的那样工作,例如:

$ export xyzzy=plugh ; export plugh=cave

$ echo ${xyzzy}  # normal, xyzzy to plugh
plugh

$ echo ${!xyzzy} # indirection, xyzzy to plugh to cave
cave
于 2011-12-15T05:22:15.357 回答
26

当给定的“间接”以 a 结尾时,似乎有一个例外*,就像这里一样。在这种情况下,它会给出以您指定的部分开头的所有变量名称(N此处)。Bash 可以做到这一点,因为它跟踪变量并知道哪些变量存在。

真正的间接是这样的:
假设我有一个变量$VARIABLE设置为42,我有另一个变量$NAME设置为VARIABLE${!NAME}会给我42。您使用一个变量的值来告诉您另一个变量的名称:

$ NAME="VARIABLE"
$ VARIABLE=42
$ echo ${!NAME}
42
于 2011-12-15T05:26:01.983 回答
3

是的,它会在 ! 之后搜索所有可能的变量扩展。如果你做了:

echo ${!NP*}

你只会得到NPX_PLUGIN_PATH.

考虑以下示例:

:~> export myVar="hi"
:~> echo ${!my*}
    myVar
:~> export ${!my*}="bye"
:~> echo $myVar
    bye
于 2011-12-15T05:20:52.773 回答
3

您在间接处理中遇到了异常,如果最后一个字符是*,则将返回所有具有之前给定前缀的变量。

于 2011-12-15T05:21:28.940 回答
1

bash间接和/或nameref

在这个问题上迟到了,因为没有其他答案可以说明nameref ...

使用${!var} 间接语法:

~$ someVariable='Some content'
~$ var=someVariable

~$ echo $var
someVariable

~$ echo ${!var}
Some content

使用namref ( declare -n) 语法

通过使用nameref,您不仅可以显示变量的内容,还可以填充变量并获取或设置属性。

~$ someVariable='Some content'
~$ declare -n var=someVariable
~$ echo $var
Some content

此语法对函数很有用:

function showVarDetail() {
    local -n var=$1
    printf 'Variable \47\44%s\47 is %d len, has [%s] flags and contain: %q\n' \
        "$1" "${#var}" "${var@a}" "$var"
}

(注意:此函数只是一个示例。这不会正确扩展数组关联数组!)

然后

~$ someVar='Hello world!'
~$ showVarDetail someVar
Variable '$someVar' is 12 len, has [] flags and contain: Hello\ world\!

~$ declare -r PI=3.14159265358979323844
~$ showVarDetail PI
Variable '$PI' is 22 len, has [r] flags and contain: 3.14159265358979323844

使用nameref 填充变量值

这可以双向工作!

这是一个使用两个变量名作为参数运行的小示例函数。第一个变量应该包含一个字符串,第二个变量将由第一个变量内容的第一个字符填充,然后第一个变量内容将移动 1 个字符:

shift1char <variable string source> <variable target>
shift1char () { 
    local -n srcStr=$1 tgtVar=$2;
    tgtVar=${srcStr::1} srcStr=${srcStr:1}
}

然后

~$ someVar='Hello world!'

~$ shift1char someVar someChar

~$ showVarDetail someVar
Variable '$someVar' is 11 len, has [] flags and contain: ello\ world\!

~$ showVarDetail someChar
Variable '$someChar' is 1 len, has [] flags and contain: H
于 2021-11-11T07:01:25.507 回答
0

您可以参考此 GNU 文档以获取 bash 的权威信息

https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion

但基本上,间接扩展不会 ${!prefix*} 作为例外之一执行,在您的示例中,N 是前缀。

文档将解释什么是 bash 中的间接扩展

于 2019-03-26T11:14:18.367 回答