2011-05-06 53 views
16

一个人为的例子...给出猛砸坏替换与子shell和子

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 

我的问题是哪个规则导致[子外壳替代]不正确地评估?如果有的话,在1跳中做到这一点的正确方法是什么?

回答

10

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

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

至于如何在一个赋值中执行此操作,请使用其他响应中提到的其他命令的管道。

6

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

在这种情况下,你可能管的basename输出到dd命令,像

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

(如果你想有一个较高的数量,增加count而不是bs,否则你可能会得到比请求更少的字节)

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

6

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

我不知道在单个表达式中执行此操作的方法。

0

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

例如:

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

巴兹= “foo” 的

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

回波$ BAZ

结果我s'f'

1

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

相反的:

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

用途:

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

你人为的例子做作的解决方案:

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

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