【问题标题】: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 是否在那里搜索了所有可能的命令?

【问题讨论】:

    标签: bash indirection


    【解决方案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”并导出。不是很有用。
          猜你喜欢
          • 2014-01-06
          • 1970-01-01
          • 1970-01-01
          • 2017-06-29
          • 1970-01-01
          • 1970-01-01
          • 2011-06-20
          • 1970-01-01
          相关资源
          最近更新 更多