什么是间接扩展? $!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* 是什么意思?的主要内容,如果未能解决你的问题,请参考以下文章