網中人“shell十三問之變數替換” 外傳(初學shell必看)(轉)

ba發表於2007-08-11
網中人“shell十三問之變數替換” 外傳(初學shell必看)(轉)[@more@]初看第八問,不解。想:其它初學shell者亦同。故解之!

變數替換:
一:簡單賦值和替換
a=bcd
$ echo $a
bcd
$ echo ${a}
bcd

二:變數擴充
除了shell中的meta,其它的[^a-zA-Z0-9_]幾乎都可以作單詞邊界。
同sed中關於單詞邊界[^a-zA-Z0-9_]的描述。

這些功能有時候會在程式中有意想不到的作用!
例如:
$ a=bcd
$ echo ${a}.b
bcd.b
$ echo $a.php
bcd.php
$ echo $a%b
bcd%b
$ echo /$a/bc
/bcd/bc
對於shell中的meta字元,則backslash。
$ echo $a*b
bcd*b

三:變數中的變數
$ a=bcd
$ b=efg
$ c=$a$b
$ echo $c
bcdefg
$ d=$c.ghi
$ echo $d
bcdefg.ghi

思考:若變數互相巢狀,會怎樣呢?

四:變數的特異功能
到網中人的啦!(ps:重寫真是沒激情啊)
file=/dir1/dir2/dir3/my.file.txt
我們可以用 ${ } 分別替換獲得不同的值:
${file#*/}:從變數file的字串左邊開始,刪除字元直到第一個“/”:dir1/dir2/dir3/my.file.txt
${file##*/}:從變數file的字串左邊開始,刪除字元直到最後一個“/”:my.file.txt
${file#*.}:從變數file的字串左邊開始,刪除字元直到第一個“.”:file.txt
${file##*.}:從變數file的字串左邊開始,刪除字元直到最後一個“.”:txt

其實,在“#”後面,無非就是一個匹配問題,不限於兩個,你可以放任意個字元,還可以用shell中另外的萬用字元“?”“[…]”“[!…]”,例如:
$ echo ${file#????}
1/dir2/dir3/my.file.txt
$ echo ${file#*[0-9]}
/dir2/dir3/my.file.txt
$ echo ${file#/dir1/dir[0-9]}
/dir3/my.file.txt

“#”:相當於最小匹配,遇到一個最小的符合其後表示式的字串(單個或多個)即中止匹配動作;
“##”:相當於最大匹配,它儘可能的匹配更多的字元。
我們可以拿“*”來說明:
* 在shell中表示匹配任何符號包括空。當它在只有一個 # 的變數替換中,受最小匹配的影響,它不會匹配任何可列印字元,只匹配一個空,也就是什麼也不匹配,你完全可以忽略它的存在;
當在有兩個 ## 的變數替換中,受最大匹配的影響,一個 * 表示匹配整個字串。
如果想匹配字元“*”時,要在“*”前加一個“”,其後的“*”失去萬用字元的功能。
但是還有一種例外情況(請接著看)

例:
$ file2=abcd.efgh.ijkl.oopp
$ echo ${file2#*.*.*.*}
$ echo ${file2##*.*.*.*}

想想上面兩個的輸出是什麼?
$ echo ${file2#*.*.*.*}
oopp
$ echo ${file2##*.*.*.*}

??知道為什麼嗎?因為:“*”匹配任何符號包括空。遇到一個“#”時,最後一個“*”就匹配“空”去了。看下面的:
$ echo ${file2#*.*.*.?}
opp
$ echo ${file2#*.*.*.?*}
opp
$ echo ${file2##*.*.*.?}
opp
$ echo ${file2##*.*.*.?*}

do you know?

$ echo $file3
*ab*de*cd
看看下面將輸出什麼?
$ echo ${file3#*ab}
*de*cd
$ echo ${file3#**}
*ab*de*cd
$ echo ${file3##**}

$ echo ${file3#*ab}
*de*cd
$ echo ${file3#**}
ab*de*cd
$ echo ${file3##**}

$ echo ${file3#*a}
b*de*cd
$ echo ${file3#*a}
b*de*cd

不知各位有沒有發現,“*”在一個“#”中時,並不一定代表“空”,它可能代表一個字元“*”也可能代表其他的什麼字元,如上例的:
“$ echo ${file3#*a}”輸出為“b*de*cd”,其實這還是符合最小匹配理論的。這個表示式的意思是:從變數file3的字串左邊開始刪除字元,直到遇到第一個字元“a”。所以不要和“$ echo ${file3#*a}”混淆,雖然兩個結果是一樣,但意思是不一樣的。
再舉幾個例子,相信大家更容易理解這段話:
$ echo $file3
*ab*de*cd*ab*de //注意:出現兩個“*ab”
$ echo ${file3#*a}
b*de*cd*ab*de //刪除字元,直到出現第一個“a”,“*”為萬用字元
$ echo ${file3##*a}
b*de //刪除字元,直到出現第二個“a”,“*”為萬用字元
$ echo ${file3##*a}
b*de*cd*ab*de //刪除字串“*a”,“*”在“”表示字元“*”

除了萬用字元“*”比較難理解一點,其他的shell萬用字元就都很容易了。

至於“%”,和“#”不同的地方,就是從變數字串右部開始。
${file%/*}:從右部開始拿掉字元,直到遇到(從右部數起的)第一個“/” :/dir1/dir2/dir3
${file%%/*}:從右部開始拿掉字元,直到遇到(從右部數起的)最後一個“/”:(空值)
${file%.*}:從右部開始拿掉字元,直到遇到(從右部數起的)第一個“.”:/dir1/dir2/dir3/my.file
${file%%.*}:從右部開始拿掉字元,直到遇到(從右部數起的)最後一個“.”:/dir1/dir2/dir3/my

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-947151/,如需轉載,請註明出處,否則將追究法律責任。

相關文章