什么是间接扩展? $!var* 是什么意思?

Posted

技术标签:

【中文标题】什么是间接扩展? $!var* 是什么意思?【英文标题】:What is indirect expansion? What does $!var* mean?什么是间接扩展? $!var* 是什么意思? 【发布时间】:2012-01-20 20:56:44 【问题描述】:

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

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

给出的例子是:

franky ~> echo $!N*
NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

这里我不太明白:

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

因为PARAMETER 就是!N*,那么

PARAMETER的其余部分

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

【问题讨论】:

【参考方案1】:

bash indirection 和/或 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

【讨论】:

【参考方案2】:

你可以参考这个 GNU 文档以获得 bash 的权威信息

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

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

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

【讨论】:

【参考方案3】:

如果你阅读了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

【讨论】:

感谢您的回答。我阅读“Bash 初学者指南”的次数越多,我就越会问自己作者是否理解她所写的内容。【参考方案4】:

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

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

$ NAME="VARIABLE"
$ VARIABLE=42
$ echo $!NAME
42

【讨论】:

【参考方案5】:

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

【讨论】:

那么除了*的情况,这和$$VAR一样吗? @chronospoon, $$VAR,更简短地写为$$VAR,是不合法的,因为$VAR返回一个字符串,它不能跟在$符号后面;要将字符串用作变量名,您需要引入一层间接性(如原始问题本身所引用的那样),ie 您可以使用$!VAR,它完全符合您的预期(错误地但可以理解)$$VAR 确实如此。【参考方案6】:

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

echo $!NP*

你只会得到NPX_PLUGIN_PATH

考虑以下示例:

:~> export myVar="hi"
:~> echo $!my*
    myVar
:~> export $!my*="bye"
:~> echo $myVar
    bye

【讨论】:

其他匹配 my* 的变量是否也设置为“bye”? @Anthony我试过了,如果$!my*扩展为myA,myB,myA用当前值导出,myB设置为“bye”并导出。不是很有用。

以上是关于什么是间接扩展? $!var* 是什么意思?的主要内容,如果未能解决你的问题,请参考以下文章

Linux shell 脚本 间接获取输入参数的方法

扩展名为dll的文件是啥意思啊?有啥用?

shellLinux shell 直接赋值和间接赋值

bash中的间接变量赋值

外汇直接标价和间接标价之间有什么区别?

DevExpress为啥要安装 直接引用DLL不行么