一次性操作多個檔案時,命令列提供萬用字元(wildcards),用一種很短的文字模式(通常只有一個字元),簡潔地代表一組路徑。
萬用字元又叫做 globbing patterns。因為 Unix 早期有一個/etc/glob
檔案儲存萬用字元模板,後來 Bash 內建了這個功能,但是這個名字被保留了下來。
萬用字元早於正規表示式出現,可以看作是原始的正規表示式。它的功能沒有正則那麼強大靈活,但是勝在簡單和方便。
本文介紹 Bash 的各種萬用字元。
一、? 字元
?
字元代表單個字元。
# 存在檔案 a.txt 和 b.txt $ ls ?.txt a.txt b.txt
上面命令中,?
表示單個字元,所以會同時匹配a.txt
和b.txt
。
如果匹配多個字元,就需要多個?
連用。
# 存在檔案 a.txt、b.txt 和 ab.txt $ ls ??.txt ab.txt
上面命令中,??
匹配了兩個字元。
注意,?
不能匹配空字元。也就是說,它佔據的位置必須有字元存在。
二、* 字元
*
代表任意數量的字元。
# 存在檔案 a.txt、b.txt 和 ab.txt $ ls *.txt a.txt b.txt ab.txt # 輸出所有檔案 $ ls *
上面程式碼中,*
匹配任意長度的字元。
*
可以匹配空字元。
# 存在檔案 a.txt、b.txt 和 ab.txt $ ls a*.txt a.txt ab.txt
三、[...] 模式
[...]
匹配方括號之中的任意一個字元,比如[aeiou]
可以匹配五個母音字母。
# 存在檔案 a.txt 和 b.txt $ ls [ab].txt a.txt b.txt $ ls *[ab].txt ab.txt a.txt b.txt
[start-end]
表示一個連續的範圍。
# 存在檔案 a.txt、b.txt 和 c.txt $ ls [a-c].txt a.txt b.txt c.txt # 存在檔案 report1.txt、report2.txt 和 report3.txt $ ls report[0-9].txt report1.txt report2.txt report3.txt
四、[^...]
和 [!...]
[^...]
和[!...]
表示匹配不在方括號裡面的字元(不包括空字元)。這兩種寫法是等價的。
# 存在檔案 a.txt、b.txt 和 c.txt $ ls [^a].txt b.txt c.txt
這種模式下也可以使用連續範圍的寫法[!start-end]
。
$ echo report[!1-3].txt report4.txt report5.txt
上面程式碼中,[!1-3]
表示排除1、2和3。
五、{...} 模式
{...}
表示匹配大括號裡面的所有模式,模式之間使用逗號分隔。
$ echo d{a,e,i,u,o}g dag deg dig dug dog
它可以用於多字元的模式。
$ echo {cat,dog} cat dog
{...}
與[...]
有一個很重要的區別。如果匹配的檔案不存在,[...]
會失去模式的功能,變成一個單純的字串,而{...}
依然可以展開。
# 不存在 a.txt 和 b.txt $ ls [ab].txt ls: [ab].txt: No such file or directory $ ls {a,b}.txt ls: a.txt: No such file or directory ls: b.txt: No such file or directory
上面程式碼中,如果不存在a.txt
和b.txt
,那麼[ab].txt
就會變成一個普通的檔名,而{a,b}.txt
可以照樣展開。
大括號可以巢狀。
$ echo {j{p,pe}g,png} jpg jpeg png
大括號也可以與其他模式聯用。
$ echo {cat,d*} cat dawg dg dig dog doug dug
上面程式碼中,會先進行大括號擴充套件,然後進行*
擴充套件。
六、{start..end} 模式
{start..end}
會匹配連續範圍的字元。
$ echo d{a..d}g dag dbg dcg ddg $ echo {11..15} 11 12 13 14 15
如果遇到無法解釋的擴充套件,模式會原樣輸出。
$ echo {a1..3c} {a1..3c}
這種模式與逗號聯用,可以寫出複雜的模式。
$ echo .{mp{3..4},m4{a,b,p,v}} .mp3 .mp4 .m4a .m4b .m4p .m4v
七、注意點
萬用字元有一些使用注意點,不可不知。
(1)萬用字元是先解釋,再執行。
Bash 接收到命令以後,發現裡面有萬用字元,會進行萬用字元擴充套件,然後再執行命令。
$ ls a*.txt ab.txt
上面命令的執行過程是,Bash 先將a*.txt
擴充套件成ab.txt
,然後再執行ls ab.txt
。
(2)萬用字元不匹配,會原樣輸出。
Bash 擴充套件萬用字元的時候,發現不存在匹配的檔案,會將萬用字元原樣輸出。
# 不存在 r 開頭的檔名 $ echo r* r*
上面程式碼中,由於不存在r
開頭的檔名,r*
會原樣輸出。
下面是另一個例子。
$ ls *.csv ls: *.csv: No such file or directory
另外,前面已經說過,這條規則對{...}
不適用
(3)只適用於單層路徑。
上面所有萬用字元只匹配單層路徑,不能跨目錄匹配,即無法匹配子目錄裡面的檔案。或者說,?
或*
這樣的萬用字元,不能匹配路徑分隔符(/
)。
如果要匹配子目錄裡面的檔案,可以寫成下面這樣。
$ ls */*.txt
(4)可用於檔名。
Bash 允許檔名使用萬用字元。這時,引用檔名的時候,需要把檔名放在單引號裡面。
$ touch 'fo*' $ ls fo*
上面程式碼建立了一個fo*
檔案,這時*
就是檔名的一部分。
八、參考連結
(完)