使用subshel​​l和substring打击坏替换

时间:2011-05-06 21:59:11

标签: bash string substitution subshell

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

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

6 个答案:

答案 0 :(得分:11)

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

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)不是参数允许的可能性之一。

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

答案 1 :(得分:6)

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

在这种情况下,您可以将basename的输出传递给dd命令,例如

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

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

在一般情况下,在一项任务中无法做到这样的事情。

答案 2 :(得分:6)

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

我不知道在单个表达式中做到这一点的方法。

答案 3 :(得分:1)

正如其他人所说,$ {}的第一个参数需要是一个变量名。但是你可以使用另一个子shell来估计你想要做的事情。

而不是:

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

使用:

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

答案 4 :(得分:0)

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

例如:

FOO = “/富/酒吧/ baz” 的

巴兹= “foo” 的

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

回声$ BAZ

结果是'f'

答案 5 :(得分:0)

为您的人为例子设计的解决方案:

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

,如

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