Shell中的萬用字元
1. 萬用字元(Wildcard)
在 Shell 中命令中,通常會使用萬用字元表示式來匹配一些檔案,如以下命令可以查詢當前目錄下所有後綴為 .xml 的檔案
find . -name "*.xml"
Shell 中可以使用的萬用字元如下:
萬用字元 | 含義 | 例項 |
---|---|---|
* | 匹配 0 或多個字元 |
a*b
,a與b之間可以有任意長度的任意字元, 也可以一個也沒有, 如 aabcb, axyzb, a012b, ab |
? | 匹配任意單個字元 |
a?b
,a與b之間有且只有一個字元, 可以是任意字元, 如 aab, abb, acb, a0b |
[list] | 匹配 list 中的任意單個字元 |
a[xyz]b
,a與b之間必須也只能有一個字元, 但只能是 x 或 y 或 z, 如 axb, ayb, azb。 |
[!list] | 匹配除 list 中的任意單一字元 |
a[!0-9]b
,a與b之間必須也只能有一個字元, 但不能是阿拉伯數字, 如 axb, aab, a-b。 |
[c1-c2] | 匹配 c1-c2 中的任意單一字元 |
a[0-9]b
,匹配0與9之間其中一個字元,如 a0b, a1b... a9b |
{s1,s2,...} | 匹配 s1 或 s2 (或更多)中的一個字串 |
a{abc,xyz,123}b
,a與b之間只能是abc或xyz或123這三個字串之一 |
2. 轉義字元
有的時候,我們匹配的內容裡面會存在*
,?
,[
等萬用字元中的符號。為了表示他們原來的意思,我們需要使用轉義字元\
,如a\[ac\]c
表示匹配a[a]c
或a[c]c
。\
本身用\\
表示。
3. 例子
有時,我們需要對當前目錄中的所有檔案進行操作,比如用tar
命令將當前目錄下的所有檔案打包,又如用scp
命令將當前目錄下的所有檔案傳輸到另一臺主機上。以scp
的使用為例,我們可能會這麼寫這個命令:
scp -r * username@hostname:path
但是,有的時候會發現一些奇怪的問題。比如說,我在本機開著 vim 編輯著一個檔案,編輯完了之後w
儲存,然後用上面的命令把當前目錄下的檔案傳到另一臺主機。如果你在另一臺主機上用 vim 開啟這個檔案,vim 會報錯,
Swap file ".filename.swp" already exists!
這是因為 vim 在開啟一個檔案編輯時,會產生一個 Swap file,這個 file 裡面存的是編輯時對文件產生的改變,當 Vim 崩潰了之類的問題發生時,可以從這個 Swap file 恢復。Swap file 會在退出該文件時被移除。如果使用者試圖開啟一個已存在 Swap file 的文件時,vim 就會報錯,防止多個使用者同時編輯同個檔案的情況的發生。
由於之前只儲存了文件而沒有退出,所以這個暫時性的 Swap file 還存在當前目錄中,隨著scp
命令一起被傳送到了目標主機中。
在我們的期望中,是不希望這個暫時性的檔案被傳輸的。由於 Swap file 的格式為 .filename.swp。我們可在開頭的.
做文章,讓scp
不傳輸以.
開頭的檔案。
scp -r [!.]* username@hostname:path
以.
開頭的檔案一般為配置檔案,快取之類,通常都是不希望被傳輸的。(有時候傳輸了之後,發現有問題,但是ls
了半天也沒找出問題,因為他們預設是隱藏的,用ls -a
才能檢視)。
4. 分清楚萬用字元表示式和正則表示式
萬用字元看起來和正則表示式很像,但他們並不是同一種東西。正則表示式中的那些量詞的匹配規則和這裡提到的幾個萬用字元的匹配規則並不相同。
如正則表示式中*
表示重複前一個字元任意次, 而萬用字元表示式中*
表示 0 或多個任意字元。在正則表示式中,ab*
表示的是那些a
後面跟 0 個或多個b
的字串,而萬用字元表示式中ab*
表示的是那些ab
後面跟任意個字元的字串。
而且正則表示式一般是部分匹配的
,用來匹配內容中的一部分,如用正則表示式a
去匹配bac
這段字串時,匹配是成功的,匹配到的內容是a
。但是萬用字元表示式的話是全部匹配的
,表示式要匹配整個字串才算匹配成功,如用正則表示式a
取匹配bac
這段字串時,匹配是失敗的。
在 Shell 命令中,通常用萬用字元表示式來匹配檔名
,而用正則表示式來匹配一段文字內容
。以grep
命令為例,grep
命令可以在指定的檔案中,挑選出和表示式匹配的那些行,其中指定檔案是用的萬用字元表示式,而文字內容的匹配用的是正則表示式。
今天使用grep
時,就因為沒分清楚他們,忙活了半天。情況是這樣的,我想看一個 jar 包裡是不是有 pom 相關的檔案,所以就輸入了下面命令
jar tf maven-model-builder-3.5.3.jar | grep 'pom*'
結果輸入了一堆檔案,而且很多檔案都沒有 pom 這串字串的。輸出內容是這樣的:
... org/apache/maven/model/composition/ org/apache/maven/model/interpolation/ org/apache/maven/model/superpom/ org/apache/maven/model/composition/DependencyManagementImporter.class ...
這就是因為我把萬用字元表示式和正則表示式搞混了,後來知道原因後,用下面的命令才得到想要的內容。
jar tf maven-model-builder-3.5.3.jar | grep 'pom.*'
使用 Shell 命令時,要分清楚哪裡用的是萬用字元表示式,哪裡用的是正則表示式。