網路農夫 --  Home 網路農夫 --  Home
網路農夫 --  Home
wait.....

3-3 檔名擴展(Filename expansion)運用

在 UNIX 系統中有時難免會用上長長的路徑,長長的檔案名稱或一大堆的檔名在指令中,所以在 C Shell 中提供了幾個符號來幫助我們解決這使用上的困擾。這就是檔名擴展的功能,也有人稱它為 wildcard。相信你對“*”這個符號一定不會陌生才對。你一定常運用它來代表所有相關的檔案名稱,它便是包含在這個檔名擴展的功能之一。以下讓我們通盤地看一看整個的檔名擴展功能。

 

3-3-1 符號“*”與“?”

 

一般使用者使用符號“*”的比例可能遠多過使用符號“?”。這可能是因為符號“*”代表任何的字元(包含 null)。而符號“?”僅用以代表任何一個單一的字元。這差別是相當大的。讓我們來看一個例子:

1 % ls
a a1 a2 aa aaa
2 % ls a*
a a1 a2 aa aaa

第一個指令 ls 告訴我們共有五個檔案,當我們以“a*”來顯示相關檔案時,五個檔案全出現了,其中檔案a的出現證明了符號“*”連 null 都代表的特性。而檔案 aaa 的出現告訴了我們一個符號“*”便可代表多個字元。接下來我們把符號“*”換成符號“?”來看看結果的差異性。

3 % ls a?
a1 a2 aa

你可發現檔案 a 沒出現,因為符號“?”不代表 null;檔案 aaa 也沒出現,這是因為符號“?”僅代表一個字元。如果你必需用 a?? 才行,如下:

4 % ls a??
aaa

看清楚僅有檔案 aaa 出現而已,a1、a2、aa 等只有兩個字元不符合條件。所以說使用者為了在使用上的方便,會運用符號“*”多過符號“?”大概就是這個原因吧!但有一點必須說明當你在撰寫 shell 程式時,如果需要使用類似的功能時,別忘了符號“?”是比較嚴謹的安全的作法,不妨改便你的使用習慣看看。因為撰寫 shell 程式要應付的情況較多,嚴謹一點的作法比較不會產生 bug。

 

對於“*”這個符號,真可說是懶人之“星”。像指令 cd 到某目錄時,目錄名稱打到一半接著“*”代表之。ls、vi、lpr、cp、rm 等等等的指令也均如法泡製。

在符號“*”的運用上也不盡然是所有指令都能接受的,像指令 mv、cp 便會有語法上無法接受“*”代表檔案的情況,看下面:

 

% mv acct.* acctold.*
usage: mv [-if] f1 f2 or mv [-if] f1 ... fn d1 (`fn' is a file or directory)
% cp acct.* acctold.*
Usage: cp [-ip] f1 f2; or: cp [-ipr] f1 ... fn d2

 

哈哈!太懶了!!被電腦“教訓”了一頓!!!不過說實在的作者我一直認為懶惰是人類發明創造的原動力!一切的偉大發明皆來自於偉大的懶惰。指令不能滿足我們的懶惰,則我們自己便應該為自己創造出一個屬於自己的“懶惰功能”來。在 Shell 程式設計單元中你將可為自己的懶惰感到無比的光榮。

 

3-3-2 符號“[...]”

 

這個符號的功能在為你定義字元、數字的範圍;它可以代表一個範圍內的一群數字或者是字母,也可代表很多個獨立的字元,或者是數字。在使用上相當具有彈性。要使用該符號“[...]”代表一個範圍時,範圍必須由小到大,兩者之間以符號“-”連接。

[0-9] 代表0、1、2、3、4、5、6、7、8、9等數字

[a-z] 代表字母a、b、c、d、...、x、y、z

[A-Za-z] 代表大寫字母A到Z或小寫字母a到z,既大小寫字母全部。

[A-z] 同上

[9-4] 範圍錯誤(錯誤示範)

[z-a] 範圍錯誤(錯誤示範)

要代表多個單獨的字元,只要一個個字元加入括號中便可。如下所示:

[abs] 代表 a 或 b 或 s

[1235] 代表 1 或 2 或 3 或 5

[ab][12] 代表 a1 或 a2 或 b1 或 b2

再提醒你一次,範圍只能由小到大,不可由大到小。如果用由大到小的方式雖然不會產生錯誤訊息,但結果一定是錯誤的。這一點自己可上機試試!以下我們來看一些實際運用的例子:

想一次顯示兩種尾號不同的所有檔案時,如下例所示:

% ls *.[sc]
backup1.c backup3.s backup2.c backup4.s

想將某個範圍的資料檔案彙整成一個新檔案,比方如上面這四個檔案合起來建一個新檔案。用法如下:

% cat backup[1-4].[sc] > backup.new

又譬如要將 aa1、aa2、aa3 三個目錄下的檔案拷貝到另一個目錄 all 之下,也可以使用得上。如下例:

% cp aa[1-3]/* ~/all/.

但是這個符號如果運用到 mkdir 指令時會產生錯誤的,這點請注意。比方你想一次新建五個目錄 disk1、disk2、disk3、disk4、disk5。假定你使用以下的方式:

% mkdir disk[1-5]

No match.

錯誤訊息告訴你“No match.”,錯在那裡呢?事實上,在使用的語法來說並沒有錯。只不過是 mkdir 指令無法接受這種用法,所以造成指令無法執行成功,產生了錯亂的訊息輸出。雖是如此,但這個法則的可組合運用還是相當好用的。請愛用善用之。

 

3-3-3 符號“{,,,}”

 

在前一個符號的最後指令 mkdir 的例子中,該符號做不到的,這個符號“{,,,}”可幫你做到。語法如下:

% mkdir disk{1,2,3,4,5}

就這樣一次新建五個目錄 disk1、disk2、disk3、disk4、disk5。或者是像以下的運用:

% mkdir man/{cat,man}{1,2,3,4,5,6,7,8}

一道 mkdir 指令一次建立 16 個目錄。簡單好用的很。

 

有時它的功能會讓人覺得蠻接進符號“[...]”的,但它們所適合處理的情況其實並不太相同。符號“[...]”所適合處理的是比較簡單化的字元,較複雜無規則性的字元則使用符號“{,,,}”比較恰當。假如我們要將三個存放在 /usr/include 目錄下的檔案一起拷貝到到 ~/time 目錄下,檔案名稱分別為 time.h、stdlib.h、termio.h,這如果要運用前面符號“[...]”來“簡化”指令,根本是不可能的事。但是,我們可以運用符號“{,,,}”來處理,請看下例:

% cp /usr/include/{time,stdlib,termio}.h ~/time

這就是符號“{,,,}”所適用的強處。不過符號“{,,,}”對於 “範圍” 的處理能力並不能像符號“[...]”那樣強,可以使用到符號“-”來做到像這樣“[0-9]”簡潔地代表 0 到 9 的“範圍”功能,這點倒叫人在使用上感到有些遺憾。以下讓我們來看看幾個運用符號“{,,,}”來 精簡化指令的實際例子:

% mkdir disk1-1 disk1-2 disk1-3 disk2
% mkdir disk{1{-1,-2,-3},2}
% mv disk2 disk3
% mv disk{2,3}
% diff echo2.c echo2.c.org
% diff echo2.c{,org}

3-3-4 符號“~”

 

符號“~”代表的是使用者自己的 home 目錄。它有一個比較特殊的用法,就是在符號“~”之後如果接上另一個使用者名稱,則便代表該使用者的 home 目錄。這點在路徑名稱的運用上幫助相當大。比方你要到另一個使用者 yeats 的 home 目錄下,你可以毫不考慮目前的工作目錄,及你是否知到該使用者的 home 目錄,馬上使用這個用法在 cd 指令上,便可改變工作目錄到該使用者的 home 目錄之下。如下所示:

% pwd
/user1/akira/project
% cd ~yeats
% pwd
/user2/group1/yeats

像此類的運用最適合同一個工作團體,使用者與使用者之間的檔案傳輸,如下示:

% cp backup.c ~yeats
% cp backup.c /user2/group1/yeats

以上這兩個指令做的是同一件事情,你會喜歡下那一個呢?尤其當你會搞不清楚那一個使用者的目錄在那裡時,你將會格外的喜歡上它。

 

版本:Beta-2001-05 -- 網路農夫