【问题标题】:Bash bad substitution with subshell and substring使用 subshel​​l 和 substring 进行 Bash 错误替换
【发布时间】:2011-08-20 12:29:07
【问题描述】:

一个人为的例子......给定

FOO="/foo/bar/baz"

这有效(在 bash 中)

BAR=$(basename $FOO) # result is BAR="baz"
BAZ=${BAR:0:1}       # result is BAZ="b"

这不是

BAZ=${$(basename $FOO):0:1} # result is bad substitution

我的问题是哪个规则导致这个 [子shell 替换] 评估不正确?如果有的话,在 1 跳中执行此操作的正确方法是什么?

【问题讨论】:

    标签: bash string substitution subshell


    【解决方案1】:

    ${parameter#word}等参数替换的修改形式只能修改参数,不能修改任意字。

    在这种情况下,您可以将basename 的输出通过管道传输到 dd 命令,例如

    BAR=$(basename -- "$FOO" | dd bs=1 count=1 2>/dev/null)
    

    (如果您想要更高的计数,请增加count 而不是bs,否则您获得的字节数可能比请求的少。)

    在一般情况下,没有办法在一个作业中做这样的事情。

    【讨论】:

      【解决方案2】:

      它失败了,因为${BAR:0:1} 是一个变量扩展。 Bash 期望在${ 之后看到一个变量名,而不是一个值。

      我不知道有一种方法可以在单个表达式中做到这一点。

      【讨论】:

        【解决方案3】:

        首先,请注意,当您这样说时:

        BAR=$(basename $FOO) # result is BAR="baz"
        BAZ=${BAR:0:1}       # result is BAZ="b"
        

        BAZ 的构造中的第一位是BAR,而不是您想要获取第一个字符的 。因此,即使 bash 允许变量名包含任意字符,您在第二个表达式中的结果也不会是您想要的。

        但是,关于阻止这种情况的规则,请允许我引用 bash 手册页:

        DEFINITIONS
               The following definitions are used throughout the rest  of  this  docu‐
               ment.
               blank  A space or tab.
               word   A  sequence  of  characters  considered  as a single unit by the
                      shell.  Also known as a token.
               name   A word consisting only of  alphanumeric  characters  and  under‐
                      scores,  and beginning with an alphabetic character or an under‐
                      score.  Also referred to as an identifier.
        

        再过一会儿:

        PARAMETERS
               A parameter is an entity that stores values.  It can be a name, a  num‐
               ber, or one of the special characters listed below under Special Param‐
               eters.  A variable is a parameter denoted by a name.  A variable has  a
               value  and  zero or more attributes.  Attributes are assigned using the
               declare builtin command (see declare below in SHELL BUILTIN COMMANDS).
        

        稍后当它定义您要询问的语法时:

           ${parameter:offset:length}
                  Substring Expansion.  Expands to  up  to  length  characters  of
                  parameter  starting  at  the  character specified by offset.
        

        因此,手册页中阐明的规则表明${foo:x:y} 构造必须有一个参数作为第一部分,并且参数只能是名称、数字或少数特殊参数字符之一。 $(basename $FOO) 不是参数允许的可能性之一。

        至于在一个作业中执行此操作的方法,请使用管道连接到其他响应中提到的其他命令。

        【讨论】:

          【解决方案4】:

          ${string:0:1},string必须是变量名

          例如:

          FOO="/foo/bar/baz"

          baz="foo"

          BAZ=eval echo '${'"$(basename $FOO)"':0:1}'

          回声 $BAZ

          结果是'f'

          【讨论】:

            【解决方案5】:

            正如其他人所说,${}的第一个参数需要是一个变量名。但是您可以使用另一个子shell 来近似您正在尝试做的事情。

            代替:

            BAZ=${$(basename $FOO):0:1} # result is bad substitution
            

            用途:

            BAZ=$(_TMP=$(basename $FOO); echo ${_TMP:0:1}) # this works
            

            【讨论】:

              【解决方案6】:

              为您的人为示例提供一个人为的解决方案:

              BAZ=$(expr $(basename $FOO) : '\(.\)')
              

              $ FOO=/abc/def/ghi/jkl
              $ BAZ=$(expr $(basename $FOO) : '\(.\)')
              $ echo $BAZ
              j
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-04-14
                • 1970-01-01
                • 1970-01-01
                • 2014-10-01
                • 2014-01-01
                相关资源
                最近更新 更多