23

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

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 跳中执行此操作的正确方法是什么?

4

6 回答 6

14

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

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

构造中的第一位BAZBAR,而不是您想要取其第一个字符的值因此,即使 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)不是参数的允许可能性之一。

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

于 2011-05-06T22:39:40.040 回答
7

参数替换的修改形式,例如${parameter#word}只能修改一个参数,而不是任意词。

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

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

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

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

于 2011-05-06T22:25:00.947 回答
6

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

我不知道用一个表达式来做到这一点。

于 2011-05-06T22:26:20.783 回答
4

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

代替:

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

采用:

BAZ=$(_TMP=$(basename $FOO); echo ${_TMP:0:1}) # this works
于 2016-03-06T18:14:09.297 回答
1

您的人为示例的人为解决方案:

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

如在

$ FOO=/abc/def/ghi/jkl
$ BAZ=$(expr $(basename $FOO) : '\(.\)')
$ echo $BAZ
j
于 2017-06-16T19:16:59.350 回答
0

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

例如:

FOO="/foo/bar/baz"

巴兹=“富”

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

回声 $BAZ

结果是'f'

于 2014-02-13T07:08:29.877 回答