Linux 萬用字元 與 正則表示式 的區別與詳解
背景:在linux使用過程中,經常需要查詢檔案,對命令中的萬用字元 pattern 和正則表示式的區分不是很清楚。有必要好好研究一下。
1 掃盲
1.1 萬用字元和正則表示式
當在使用命令列時,有很多時間都用來查詢你所需要的檔案,如 ls find
等。 Shell 提供了一套完整的字串模式匹配規則,或者稱之為元字元,當 Shell 遇到上述字元時,就會把它們當作特殊字元,而不是檔名中的普通字元,這樣使用者就可以用它們來匹配相應的檔名,我理解這可以稱為萬用字元。
萬用字元與正則表示式是有區別的,簡單來說:萬用字元是用來通配的,正則表示式是用來匹配字串的;
萬用字元是shell自帶的用於匹配檔名的工具,多用在檔名上,比如查詢find
ls
,cp
等等,而正則表示式則需要特定命令的支援才可以使用,如:grep
、sed
和awk
(號稱Linux三劍客)、vi/vim
、perl
等,這些都是處理文字的工具。
其次,shell對萬用字元與正則表示式的處理也有不同,“ ”
內一般為萬用字元(是shell本身提取處理),‘ ’
內一般為正則表示式(shell會將其中的資料傳遞給其它命令處理)。
-
萬用字元
常見元字元:
*
:匹配零或多個任意字元
?
:匹配任意單個字元
[]
:指定中括號內的多個字元,如:[rwc]或[r,w,c]都行
[^]
或[!]
:除了中括號內字元外匹配任一個字元
引用以下模式要在外面再套一個[],tr
命令則不用(這是規定嗎?)
[:digit:]
[:lower:]
:任意小寫字元
[:upper:]
:任意大寫字元
[:alpha:]
:任意大小寫字母
[:alnum:]
:任意一個字母或數字
[:space:]
:一個空格
[:punct:]
:標點符號 -
正則表示式
這裡不具體介紹正則表示式,只是說一下和萬用字元的區別
首先萬用字元沒有次數匹配
*
:匹配前面的字元零次或多次
.
:匹配任意一個字元
?
:前面的字元零次或一次,基本正則是?
+
:前面的字元至少一次,基本正則是+
[]
:和萬用字元完全一樣
[^]
:和萬用字元一樣,但是沒有[!]
的寫法
2 萬用字元詳細介紹
-
測試資料
touch a a6.log abc.log ac.txt b c c5.txt x.log A
-
*
代表任意多個字元
例:查詢以.log
結尾的檔案ll *.log
-
?
代表任意單個字元
例:只查詢a、b、c
ll ?
-
[]
代表[
和]
之間的某一個字元,比如[0-9]
可以代表0-9之間的任意一個數字,[a-zA-Z]
可以代表a-z
和A-Z
之間的任意一個字母,字母區分大小寫。
例:只查詢字母檔案ll [a-zA-Z]
例:查詢以.log
結尾且.log
前只有兩個字元的檔案且第二個字元是數字ll ?[0-9].log
-
^
表示匹配結果取反的意思,注意這個萬用字元必須要在[]中使用
例:查詢不是以.txt
結尾的檔案ll *[^txt]*
-
{}
表示符合括號內包含的多個檔案
例:查詢.log
和.txt
結尾的檔案ll {*.log,*.txt}
注意:.
這個符合比較特殊,如果匹配的條件加上了該符合那麼說明查詢結果檔案就包含帶.
的檔案
例如前面的^
的例子,如果我這樣查詢ll *.[^txt]*
,那麼結果就不一樣了
- 刪除操作
例如:刪除a、b、c
和以.txt
結尾的檔案
rm -f {[abc],*.txt}
當然既然可以查詢當然也可以使用萬用字元匹配的方式進行移動檔案,如果需要在存在很多檔案的資料夾中移動某些型別的檔案那麼使用萬用字元匹配的效率就顯而易見了;當時萬用字元的使用技巧不單單隻有這些,有空的可以多去研究。
3 例項
*
匹配檔名中的任何字串,包括空字串。
?
匹配檔名中的任何單個字元。
[...]
匹配[ ]中所包含的任何字元。
[!...]
匹配[ ]中非感嘆號!之後的字元。和^的效果一樣
如:
5*
5開頭的所有字串
*5
5結尾的所有字串
*5?
以5為倒數第二個字元的字串
[0-9]
所有以數字的字元
[1,2]
1或者2
[!0-9]
不是數字的字元
ls /etc/[!a-n]*.conf
列出/etc/目錄中不是以字母a到n開頭的,並且以.conf結尾的檔案
ls /etc/[a-n]*.conf
列出/etc/目錄中以字母a到n開頭的,並且以.conf結尾的檔案
ls /bin/[ck]*
列出以 c或k開頭的檔名
4 正則表示式詳細介紹
正則表示式(也稱為“regex”或“regexp”)是一種用來描述文字模式的特殊語法。在 Linux 系統上,正則表示式通常被用來查詢文字的模式,以及對文字流執行“搜尋-替換”操作以及其它功能。
-
簡單字串
$ grep bash /etc/passwd operator:x:11:0:operator:/root:/bin/bash root:x:0:0::/root:/bin/bash ftp:x:40:1::/home/ftp:/bin/bash
在上面的命令中,grep 的第一個引數是一個正則表示式;第二個引數是一個檔名。grep 讀取 /etc/passwd 中的每一行並對它應用簡單子串正則表示式 bash 來查詢匹配項。如果找到一個匹配項,那麼 grep 打印出整行;否則,忽略該行。
-
理解簡單子串
一般來說,如果您正在搜尋一個子串,那麼您可以不提供任何“特殊”字元,而只是逐字地指定文字。只有在子串包含
+
、.
、*
、[
、]
或/
(在這樣的情況下,這些字元需要用引號括起來並在它們的前面使用反斜槓)才需要做特殊的事情。下面是簡單子串正則表示式幾個其它示例:tmp (掃描查詢文字串 tmp) “\[box\]”(掃描查詢文字串 [box]) “\*funny\*”(掃描查詢文字串 *funny*) “ld\.so”(掃描查詢文字串 ld.so)
-
元字元
使用正則表示式,可以利用元字元來執行比我們至今已研究過的示例複雜得多的搜尋。這些元字元中的一個是 .(點),它與任何單個字元匹配:
$ grep dev.hda /etc/fstab /dev/hda3 reiserfs noatime,ro 1 1 /dev/hda1 /boot reiserfs noauto,noatime,notail 1 2 /dev/hda2 swap sw 0 0 #/dev/hda4 /mnt/extra reiserfs noatime,rw 1 1
在本示例中,文字文字 dev.hda 沒有出現在 /etc/fstab 中的任何一行中。但是,grep 掃描這些行時沒有查詢文字 dev.hda 字串,而是查詢 dev.hda 模式。請記住 . 將與任何單個字元相匹配。正如您看到的,. 元字元在功能上等價於 glob 擴充套件中 ? 元字元的工作原理。
-
使用 []
如果我們希望與比 . 更具體一點地來匹配字元,那麼我們可以使用 [ 和 ](方括號)來指定要匹配的字元子集:
$ grep dev.hda[12] /etc/fstab /dev/hda1 /boot reiserfs noauto,noatime,notail 1 2 /dev/hda2 swap swap sw 0 0
[\u4e00-\u9fa5]
: 表示任意一個漢字正如您看到的,這個特殊語法的作用與
glob
檔名擴充套件中的[]
相同。 -
使用 [^]
通過使
[
後面緊跟一個^
,您可以使方括號中的意思相反。在本例中,方括號將與未列在方括號內的任意字元匹配。同樣,請注意我們在正則表示式中使用[^]
,而在 glob 中使用[!]
:$ grep dev.hda[^12] /etc/fstab /dev/hda3 reiserfs noatime,ro 1 1 /dev/hda4 /mnt/extra reiserfs noatime,rw 1 1
-
區別語法
注意下面一點很重要:方括號內部的語法根本不同於正則表示式其它部分中的語法。例如,如果在方括號內放置一個 . ,那麼它允許方括號與文字 . 匹配,就象上面示例中的 1 和 2。比較起來,除非有\ 作為字首,否則方括號外面的文字 . 被解釋為一個元字元。通過輸入如下命令,我們可以利用這一事實來列印 /etc/fstab 中包含文字串 dev.hda 的所有行的列表:
$ grep dev[.]hda /etc/fstab
或者,我們也可以輸入:
$ grep "dev\.hda" /etc/fstab
這兩個正則表示式都不可能與您的/etc/fstab
檔案中的任何行相匹配。 -
*
元字元某些元字元本身不匹配任何字元,但卻修改前一個字元的含義。一個這樣的元字元是
*
(星號),它用來與前一個字元的零次或者多次重複出現相匹配。這裡是一些示例:
ab*c
(與abbbbc
匹配但不與abqc
匹配)
ab*c
(與abc
匹配但不與abbqbbc
匹配)
ab*c
(與ac
匹配但不與cba
匹配)
b[cq]*e
(與bqe
匹配但不與eb
匹配)
b[cq]*e
(與bccqqe
匹配但不與bccc
匹配)
b[cq]*e
(與bqqcce
匹配但不與cqe
匹配)
b[cq]*e
(與bbbeee
匹配)
.*
(與任何字串匹配)
foo.*
(與以foo
開始的任何字串相匹配)
ac
行與正則表示式ab*c
相匹配,因為星號也允許前面的表示式b
出現零次。請注意解釋*
正則表示式元字元所用的方法與解釋* glob
字元的方法根本不同。 -
行的開始和結束
我們在這裡要詳細描述的最後幾個元字元是
^
和$
元字元,它們用來分別與行的開始和結束相匹配。通過在正則表示式開始處使用一個 ^ ,您可以將您的模式“錨定”在行的開始。在下面的示例中,我們使用 ^# 正則表示式來與以 # 字元開始的任何行相匹配:$ grep ^# /etc/fstab # /etc/fstab: static file system information. #
-
完整行正則表示式
可以組合
^
和$
來與完整的行相匹配。例如,下面的正則表示式將與以#
字元開始並以.
字元結束的行相匹配,在其中間可以有任意多個其它字元:$ grep '^#.*/.$' /etc/fstab # /etc/fstab: static file system information.
在上面的示例中,我們用單引號將我們的正則表示式括起來以阻止
shell
解釋$
。在不使用單引號的情況下,grep
甚至沒有機會檢視$
,$
就從我們的正則表示式上消失了。 -
正則總結(轉)
元字元
.
:小數點可以匹配除\n
以外的任意一個字元。如果要匹配包括\n
在內的所有字元,一般用[\s\S]
,或者是用.
加(?s)
匹配模式來實現。
[abc]
:匹配方括號中的任意一個字元。可以使用-表示字元範圍,如[a-z0-9]
匹配小寫字母和阿拉伯數字。
[^abc]
:在方括號內開頭使用^
符號,表示匹配除方括號中字元之外的任意字元。|
: 表示或
\d
匹配阿拉伯數字,等同於[0-9]
。
\D
匹配阿拉伯數字之外的任意字元,等同於[^0-9]
。
\x
匹配十六進位制數字,等同於[0-9A-Fa-f]
。
\X
匹配十六進位制數字,等同於[^0-9A-Fa-f]
。
\w
匹配單詞字母,等同於[0-9A-Za-z_]
。
\W
匹配單詞字母之外的任意字元,等同於[^0-9A-Za-z_]
。
\t
匹配<TAB>
字元。
\s
匹配空白字元,等同於[ /t]
。
\S
匹配非空白字元,等同於[^ /t]
。
\a
所有的字母字元. 等同於[a-zA-Z]
\l
小寫字母[a-z]
\L
非小寫字母[^a-z]
\u
大寫字母[A-Z]
\U
非大寫字母[^A-Z]
-
表示數量的元字元
元字元 說明
*
匹配0-任意個
\+
匹配1-任意個
\?
匹配0-1個
\{n,m\}
匹配n-m個
\{n\}
匹配n個
\{n,\}
匹配n-任意個
\{,m\}
匹配0-m個
-
換行符 說明
\r,\n
回車和換行
\\
匹配\
\^
,\$
,\.
匹配^
$
.
以下字元在匹配其本身時,通常需要進行轉義。在實際應用中,根據具體情況,需要轉義的字元可能不止如下所列字元 :$
^
{
[
(
|
)
*
+
?
\
表示位置的符號
$
匹配行尾
^
匹配行首
\<
匹配單詞詞首
\>
匹配單詞詞尾
\b
匹配單詞邊界