2011-05-06 52 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