細讀shell-5

 19. 在結束本章之前,再跟大家補充兩個與 loop 有關的命令: 

* break 

* continue 

這兩個命令常用在複合式循環裏,也就是在 do ... done 之間又有更進一層的 loop

break 是用來打斷循環,也就是"強迫結束" 循環。 break 後面指定一個數值 n 的話,則"從裏向外"打斷第 n 個循環,

默認值爲 break 1 ,也就是打斷當前的循環。 

在使用 break 時需要注意的是, 它與 return exit 是不同的:

* break 是結束 loop 

* return 是結束 function 

* exit 是結束 script/shell 

若你理解不來的話,那你可簡單的看成:在 continue done 之間的句子略過而返回循環頂端... 

break 相同的是: continue 後面也可指定一個數值 n 以決定繼續哪一層(從裏向外計算)的循環,  默認值爲 continue 1 ,也就是繼續當前的循環。 

b1) [^ ] [! ] 差在哪? 

 

這個問題等了好久都沒人出來補充, 而我呢, 也被追殺了好幾回... ^_^ 

趁着今晚有一點空閒, 趕快將此樁心事做一了結吧... 

 

這道題目說穿了, 就是要探討 Wildcard Regular Expression 的差別的

這也是許多初學 shell 的朋友很容易混亂的地方

首先, 讓我們回到十三問之第 2 , 再一次將我們提到的 command line format 溫習一次:  

代碼:

command_name options arguments

 

同時, 也再來理解一下我在第 5 問所提到的變量替換的特性:  

代碼:

先替換, 再重組 command lline!

 

有了這兩道基礎後, 才讓我們來看看 wildcard 是甚麼回事吧

 

Part-I: Wildcard 

 

首先, wildcard 也是屬於 command line 的處理工序, 作用於 argument 裏的 path 之上

沒錯, 它不用在 command_name 也不用在 options

而且, argument 不是 path 的話, 那也與 wildcard 無關

換句更爲精確的定義來講, wildcard 是一種命令行的路徑擴展(path expansion)功能

提到這個擴展, 那就不要忘記了 command line "重組"特性了

是的, 這與變量替換(variable substitution)及命令替換(command substitution)的重組特

性是一樣的

也就是在 wildcard 進行擴展後, 命令行會先完成重組纔會交給 shell 來處理

 

瞭解了 wildcard 的擴展與重組特性後, 接下來, 讓我們瞭解一些常見的 wildcard

*: 匹配 0 或多個字符 

?: 匹配任意單一字符 

[list]: 匹配 list 中的任意單一字符(注一

[!list]: 匹配不在 list 中的任意單一字符 

{string1,string2,...}: 匹配 sring1 string2 (或更多)其一字符串 

(注一: list 可以爲指定的個別字符, abcd; 也可以爲一段 ASCII 字符的起止範圍, :

a-d .) 

 

a*b: a b 之間可以有任意長度的任意字符, 也可以一個也沒有, : aabcb, axyzb,

a012b, ab

a?b: a b 之間必須也只能有一個字符, 可以是任意字符, : aab, abb, acb, a0b

a[xyz]b: a b 之間必須也只能有一個字符, 但只能是 x y z, : axb, ayb, azb

這三個

a[!0-9]b: a b 之間必須也只能有一個字符, 但不能是阿拉伯數字, : axb, aab, a-b

a{abc,xyz,123}b: a  之間只能是 abc  xyz  123  這三個字符串之一

aabcb, axyzb, a123b 這三個

 

注意

1) [! ] 中的 ! 只有放在第一順位時, 纔有排除之功. 舉例說

[!a]* 表示當前目錄下所有不以 a 開首的路徑名稱

/tmp/[a\!]* 表示 /tmp 目錄下以 a ! 開首的路徑名稱. (思考: 爲何 ! 前面要加 \ ?

提示: 十三問之 4 ) 

2) [ -] 中的 - 左右兩邊均有字符時, 才表示一段範圍, 否則僅作 "-"(減號) 字符來處理.

例說

/tmp/*[-z]/[a-zA-Z]* 表示 /tmp 目錄下所有以 z - 結尾的子目錄下以英文字母(不分

大小寫)開首的路徑名稱

 

3) * ? 開首的 wildcard 不能匹配隱藏文件(即以 . 開首的文件). 舉例說

*.txt 並不能匹配 .txt 但可匹配 1.txt 這樣的路徑名稱

1*txt 1?txt 均可匹配 1.txt 這樣的路徑名稱

 

基本上, 要掌握 wildcard 並不難, 只要多加練習, 再勤于思考, 就能熟加運用了

再次提醒: 別忘了"擴充+重組"這個重要特性, 而且只作用在 argument path

比方說, 假設當前目錄下有 a.txt b.txt c.txt 1.txt 2.txt 3.txt 這幾份文件

當我們在命令行中下達 ls -l [0-9].txt 的命令行時

因爲 wildcard 處於 argument 的位置上, 於是根據其匹配的路徑, 擴展爲 1.txt 2.txt

3.txt , 

再重組出 ls -l 1.txt 2.txt 3.txt 這樣的命令行

因此, 你在命令行上敲 ls -l [0-9].txt ls -l 1.txt 2.txt 3.txt 都是同樣的結果, 其原因正

是於此了...  

 

 

Part-II: Regular Expression 

 

接下來的 Regular Expression(RE) 可是個大題目, 要講的很多, 我這裏當然不可能講得很完

只希望帶給大家一個基本的入門概念, 就很是足夠了... 

 

先來考一下英文好了: What is expression? 

簡單來說, 就是"表達", 也就是人們在溝通時所要陳述的內容

然而, 生活中, 表達方要清楚的將意思描述清楚而讓接收方完整且無誤的領會, 可不是件容易

的事情

因而纔會出現那麼多的"誤會", 真可嘆句"表達不易".... 

同樣的情形也發生在計算機的數據處理過程中, 尤其是當我們在描術一段"文字內容"的時候... 

那麼, 我們不禁要問: 有何方法可以讓大家的誤會降至最低程度而讓表達的精確度達到最高程

度呢

答案就是"標準化", 亦就是我們這裏要談的 Regular Expression ....  ^_^ 

 

然而, 在進入 RE 介紹之前, 不防先讓我們溫習一下 shell 十三問第 4 , 也就是關於

quoting 的部份

關鍵是要能夠區分 shell command line 上的 meta literal 這兩種不同的字符類別

然後, 我這裏纔跟你講

--- RE 表達式裏的字符也是分爲 meta literal 這兩種

, 不知親愛的讀者是否被我搞混亂了呢? ...  ^_^ 

這也難怪啦, 因爲這的確是最容易混亂的地方, 剛學 RE 的朋友很多時候都死在這裏

因此請特別小心理解哦... 

簡單而言, 除非你將 RE 寫在特定程序使用的腳本里

否則, 我們的 RE 也是透過 command line 輸入的

然而, 不少 RE 所始用的 meta 字符, shell meta 字符是衝突的

比方說, * 這個字符, RE 裏是一個 modifier(後述), command line , 卻是個

wildcard ! 

 

那麼, 我們該如何解決這樣的衝突呢? 關鍵就是看你對十三問第 4 問所提的 quoting 是否夠

理解了

若你明白到 shell quoting 就是在 command line 上關閉 shell meta 這一基本原理

那你就能很輕鬆的解決 RE meta shell meta 的衝突問題了

--- shell quoting 關掉 shell meta 就是了

就這麼簡單...  ^_^ 

再以剛提到的 * 字符爲例, 若在 command line 中沒有 quoting 處理的話, abc* , 

那就會被作爲 wildcard expansion 來擴充及重組了

若將之置於 quoting , "abc*", 則可避免 wildcard expansion 的處理. (注一

(* 注一

是否需要 quoting 得視具體的程序及具體的命令語法而定. grep 爲例

假設當前目錄下有 abc abc-xyz 這兩份文件, 其中 abc 文件的內容就是 abc 這行文字

當我們在 command line 輸入 grep abc* abc* 的時候

第一個 abc* 事實上並不需要 quoting 就可避免 wildcard 處理, 而第二個 abc* 則會被

擴展爲 abc abc-xyz . 

在命令行重組後, 將會成爲 grep abc* abc abc-xyz . 其輸出結果會是: abc:abc 

然而, 若我們的 command line 改爲 echo abc | grep abc* 的話, 若沒 quoting 處理的

, * 會被視爲 wildcard , 

在命令行重組後, 將會成爲 echo abc | grep abc abc-xyz . 將得不到任何輸出結果

要想得到結果的話, command line 應改爲: echo abc | grep "abc*" 

 

好了, 說了大半天, 還沒進入正式的 RE 介紹呢... 

大家別急, 因爲我的教學風格就是要先建立基礎, 循序漸進的...  ^_^ 

因此, 我這裏還要在囉唆一個觀念, 纔會到 RE 的說明啦... (... 別打我....) 

當我們在談到 RE , 千萬別跟 wildcard 搞混在一起

尤其在 command line 的位置裏, wildcard 只作用於 argument path

但是 RE 卻只用於"字符串處理"的程序之中, 這與路徑名稱一點關係也沒有

RE 所處理的字符串通常是指純文檔或透過 stdin 讀進的內容... 

 

okay, 夠了夠了, 我已看到一堆人開始出現不大耐煩的樣子了....  ^_^ 

現在, 就讓我門登堂入室, 撩開 RE 的神祕面紗吧, 這樣可以放過我了吧? 哈哈... 

 

RE 的表達式裏, 主要分兩種字符(character): literal meta. 

所謂 literal 就是在 RE 裏不具特殊功能的字符, abc, 123 這些

meta RE 裏具有特殊的功能, 要關閉之需在 meta 前面使用 escape( \ )字符

 然而, 在介紹 meta 之前, 先讓我們來認識一下字符組合(character set)會更好些

所謂的 char. set 就是將多個連續的字符作一個集合, 比方說

abc: 表示 abc 三個連續的字符, 但彼此獨立而非集合. (可簡單視爲三個 char. set) 

(abc): 表示 abc 這三個連續字符的集合. (可簡單視爲一個 char. set) 

abc|xyz: 表示或 abc xyz 這兩個 char. set 之一

[abc]: 表示單一字符, 可爲 a b c . ( wildcard [abc] 原理相同

[^abc]: 表示單一字符, 不爲 a b c 即可. ( wildcard [!abc] 原理相同

. : 表示任意單一字符. ( wildcard ? 原理相同

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章