歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> linux下通配符與正則表達式

linux下通配符與正則表達式

日期:2017/2/27 16:02:31   编辑:Linux教程
通配符是系統level的 而正則表達式需要相關工具的支持: egrep, awk, vi, perl。

在文本過濾工具裡,都是用正則表達式,比如像awk,sed等,是針對文件的內容的。
通配符多用在文件名上,比如查找find,ls,cp,等等。

通配符
在您日常的 Linux 使用中,有很多時候您可能需要一次對多個文件系統對象執行單一操作(比如 rm)。在這些情況下,在命令行中輸入許多文件通常讓人感到厭煩:
$ rm file1 file2 file3 file4 file5 file6 file7 file8
為了解決這個問題,您可以利用 Linux 內置的通配符支持。這種支持也叫做“globbing”(由於歷史原因),允許您通過使用通配符模式一次指定多個文件。Bash 和其它 Linux 命令將通過在磁盤上查找並找到任何與之匹配的文件來解釋這種模式。因此,如果在當前工作目錄中,您有從 file1 到 file8 的文件,那麼您可以輸入下面的命令來刪除這些文件:
$ rm file[1-8]
或者,如果您只想要刪除文件名以 file 開頭的所有文件,您可以輸入:
$ rm file*
或者,如果您想要列出 /etc 中以 g 開頭的所有文件系統對象,您可以輸入:
$ ls -d /etc/g*
/etc/gconf /etc/ggi /etc/gimp /etc/gnome /etc/gnome-vfs-mime-magic /etc/gpm /etc/group /etc/group-
現在,如果您指定了沒有任何文件系統對象與之匹配的模式,會怎麼樣呢?在下面的示例中,我們試圖列出 /usr/bin 中以 asdf 開頭並且以 jkl 結尾的所有文件:
$ ls -d /usr/bin/asdf*jkl
ls: /usr/bin/asdf*jkl: No such file or directory
這裡是對所發生情況的說明。通常,當我們指定一種模式時,該模式與底層系統上的一個或多個文件匹配,bash 以空格隔開的所有匹配對象的列表來替換該模式。但是,當模式不能找到匹配對象時,bash 將不理會參數、通配符等等,保留原樣。因此,當“ls”不能找到文件 /usr/bin/asdf*jkl 時,它會報錯。此處的有效的規則是:glob 模式只在與文件系統中的對象匹配時才可以進行擴展。

通配符語法:*
* 將與零個或多個字符匹配。這就是說“什麼都可以”。例子:
* /etc/g* 與 /etc 中以 g 開頭的所有文件匹配。
* /tmp/my*1 與 /tmp 中以 my 開頭,並且以 1 結尾的所有文件匹配。

通配符語法:?
? 與任何單個字符匹配。例子:
* myfile? 與文件名為 myfile 後跟單個字符的任何文件匹配。
* /tmp/notes?txt 將與 /tmp/notes.txt 和 /tmp/notes_txt 都匹配,如果它們存在。

通配符語法:[]
該通配符與 ? 相似,但允許指定得更確切。要使用該通配符,把您想要匹配的所有字符放在 [] 內。結果的表達式將與 [] 中任一字符相匹配。您也可以用 - 來指定范圍,甚至還可以組合范圍。例子:
* myfile[12] 將與 myfile1 和 myfile2 匹配。只要當前目錄中至少有一個這樣的文件存在,該通配符就可以進行擴展。
* [Cc]hange[Ll]og 將與 Changelog、ChangeLog、changeLog 以及 changelog 匹配。您可以看到,與大寫形式的變形匹配時,使用括弧通配符很有用。
* ls /etc/[0-9]* 將列出 /etc 中以數字開頭的所有文件。
* ls /tmp/[A-Za-z]* 將列出 /tmp 中以大寫字母或小寫字母開頭的所有文件。

通配符語法:[!]
除了不與括弧中的任何字符匹配外,[!] 構造與 [] 構造類似,只要不是列在 [! 和 ] 之間的字符,它將與任何字符匹配。例子:
* rm myfile[!9] 將刪除除 myfile9 之外的名為 myfile 加一個字符的所有文件。

通配符告誡說明
這裡有一些使用通配符時應該注意的告誡說明。由於 bash 對與通配符相關的字符(?、[、]、*)進行特別處理,因此您將包含這些字符的參數輸入到命令中時,需要特別小心。例如,如果您想要創建一個包含字符串 [fo]* 的文件,下面這個命令可能不會執行您想要做的事:
$ echo [fo]* > /tmp/mynewfile.txt
如果 [fo]* 這個模式與當前工作目錄中的任何文件匹配,那麼您將在 /tmp/mynewfile.txt 內發現那些文件的名稱,而不是您所期望的文字 [fo]*。解決方法是什麼呢?嗯,一種方法是用單引號把這些字符括起來,這將告訴 bash 單純地執行,而不會對其進行通配符擴展:
$ echo '[fo]*' > /tmp/mynewfile.txt
采用這種方法,您的新文件將包含所期望的文字的 [fo]*。另一種方法是,您可以使用反斜槓,告訴 bash [、] 和 * 應該被當成文字處理,而不是被當成通配符處理:
$ echo /[fo/]/* > /tmp/mynewfile.txt
兩種方法都能同樣地起作用。既然我們談到反斜槓擴展,那麼現在是時候提一提了,為了指定文字 /,您可以將它放入單引號中,或者也可以輸入 //(它將被擴展為 /)。
請注意雙引號的作用和單引號很接近,而雙引號還允許 bash 做一些有限的擴展。因此,當您確實想要把文字文本傳給命令時,單引號是最好的選擇。要獲取關於通配符擴展更多的信息,請輸入 man 7 glob。要獲取關於 bash 中引號作用的更多信息,請輸入 man 8 glob,並閱讀題為 QUOTING 的章節。


正則表達式
1、什麼是正則表達式?
正則表達式(也稱為“regex”或“regexp”)是一種用來描述文本模式的特殊語法。在 Linux 系統上,正則表達式通常被用來查找文本的模式,以及對文本流執行“搜索-替換”操作以及其它功能。

2、與 glob 的比較

當我們看到正則表達式時,您可能發現正則表達式的語法看起來與我們上一篇教程(請參閱本教程最後的“參考資料”一節中列出的“第 1 部分”)中研究的“文件名匹配替換”語法相類似。但是,不要讓它欺騙您;它們的類似性只是表面的。雖然正則表達式和文件名匹配替換模式可能看上去相類似,但是它們是根本不同的兩種類型。

3、簡單子串

記住那個警告,讓我們看一下最基本的正則表達式,簡單子串。為了這樣做,我們要使用 grep,它是一個掃描文件內容來查找適合特定正則表達式的命令。grep 打印與正則表達式匹配的每一行,並忽略與之不匹配的每一行:
$ 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 打印出整行;否則,忽略該行。

4、理解簡單子串

一般來說,如果您正在搜索一個子串,那麼您可以不提供任何“特殊”字符,而只是逐字地指定文本。只有在子串包含 +、.、*、[、] 或 /(在這樣的情況下,這些字符需要用引號括起來並在它們的前面使用反斜槓)才需要做特殊的事情。下面是簡單子串正則表達式幾個其它示例:
* /tmp (掃描查找文字串 /tmp)
* “/[box/]”(掃描查找文字串 [box])
* “/*funny/*”(掃描查找文字串 *funny*)
* “ld/.so”(掃描查找文字串 ld.so)

5、元字符
使用正則表達式,可以利用元字符來執行比我們至今已研究過的示例復雜得多的搜索。這些元字符中的一個是 .(點),它與任何單個字符匹配:
$ grep dev.hda /etc/fstab
/dev/hda3 / reiserfs noatime,ro 1 1
/dev/hda1 /boot reiserfs noauto,noatime,notail 1 2
/dev/hda2 swap swap sw 0 0
#/dev/hda4 /mnt/extra reiserfs noatime,rw 1 1
在本示例中,文字文本 dev.hda 沒有出現在 /etc/fstab 中的任何一行中。但是,grep 掃描這些行時沒有查找文字 dev.hda 字符串,而是查找 dev.hda 模式。請記住 . 將與任何單個字符相匹配。正如您看到的,. 元字符在功能上等價於 glob 擴展中 ? 元字符的工作原理。

6、使用 []
如果我們希望與比 . 更具體一點地來匹配字符,那麼我們可以使用 [ 和 ](方括號)來指定要匹配的字符子集:
$ grep dev.hda[12] /etc/fstab
/dev/hda1 /boot reiserfs noauto,noatime,notail 1 2
/dev/hda2 swap swap sw 0 0
正如您看到的,這個特殊語法的作用與“glob”文件名擴展中的 [] 相同。同樣,這是學習正則表達式的難點之一 — 這個語法與“glob ”文件名擴展語法類似,但又不盡相同,它經常給學習正則表達式的人帶來困惑。

7、使用 [^]
通過使 [ 後面緊跟一個 ^,您可以使方括號中的意思相反。在本例中,方括號將與未列在方括號內的任意字符匹配。同樣,請注意我們在正則表達式中使用 [^] ,而在 glob 中使用 [!] :
$ grep dev.hda[^12] /etc/fstab
/dev/hda3 / reiserfs noatime,ro 1 1
#/dev/hda4 /mnt/extra reiserfs noatime,rw 1 1

8、區別語法
注意下面一點很重要:方括號內部的語法根本不同於正則表達式其它部分中的語法。例如,如果在方括號內放置一個 . ,那麼它允許方括號與文字 . 匹配,就象上面示例中的 1 和 2。比較起來,除非有 / 作為前綴,否則方括號外面的文字 . 被解釋為一個元字符。通過輸入如下命令,我們可以利用這一事實來打印 /etc/fstab 中包含文字串 dev.hda 的所有行的列表:
$ grep dev[.]hda /etc/fstab
或者,我們也可以輸入:
$ grep "dev/.hda" /etc/fstab
這兩個正則表達式都不可能與您的 /etc/fstab 文件中的任何行相匹配。

9、“*”元字符
某些元字符本身不匹配任何字符,但卻修改前一個字符的含義。一個這樣的元字符是 * (星號),它用來與前一個字符的零次或者多次重復出現相匹配。這裡是一些示例:
* 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 字符的方法根本不同。

10、行的開始和結束
我們在這裡要詳細描述的最後幾個元字符是 ^ 和 $ 元字符,它們用來分別與行的開始和結束相匹配。通過在正則表達式開始處使用一個 ^ ,您可以將您的模式“錨定”在行的開始。在下面的示例中,我們使用 ^# 正則表達式來與以 # 字符開始的任何行相匹配:
$ grep ^# /etc/fstab
# /etc/fstab: static file system information.
#

11、完整行正則表達式
可以組合 ^ 和 $ 來與完整的行相匹配。例如,下面的正則表達式將與以 # 字符開始並以 . 字符結束的行相匹配,在其中間可以有任意多個其它字符:
$ grep '^#.*/.$' /etc/fstab
# /etc/fstab: static file system information.
在上面的示例中,我們用單引號將我們的正則表達式括起來以阻止 shell 解釋 $ 。在不使用單引號的情況下,grep 甚至沒有機會查看 $,$ 就從我們的正則表達式上消失了。




vim正則應用舉例:
:g/^/s*$/d 刪除只有空白的行
:s//(/w/+/)/s/+/(/w/+/)//2/t/1 將 data1 data2 修改為 data2 data1
:%s//(/w/+/), /(/w/+/)//2 /1/ 將 Doe, John 修改為 John Doe
:%s//<id/>//=line(".") 將各行的 id 字符串替換為行號
:%s//(^/</w/+/>/)//=(line(".")-10) .".". submatch(1)
將每行開頭的單詞替換為(行號-10).單詞的格式,如第11行的word替換成1. word
排序 :/OB/+1,$!sort

1,去掉所有的行尾空格:":%s//s/+$//"。"%"表示在整個文件范圍內進行替換,"/s"表示空白字符(空格和制表符),"/+"對前面的字符匹配一次或多次(越多越好),"tiny_mce_markerquot;匹配行尾(使用"/$表示單純的"$字符);被替換的內容為空;由於一行最多只需替換一次,不需要特殊標志。這個還是比較簡單的。
2,去掉所有的空白行:":%s//(/s*/n/)/+//r/"。這回多了"/("、"/)"、"/n"、"/r"和 "*"。"*"代表對前面的字符(此處為"/s")匹配零次或多次(越多越好;使用"/*"表示單純的"*"字符),"/n"代表換行符,"/r"代表回車符,"/("和"/)"對表達式進行分組,使其被視作一個不可分割的整體。因此,這個表達式的完整意義是,把連續的換行符(包含換行符前面可能有的連續空白字符)替換成為一個單個的換行符。唯一很特殊的地方是,在模式中使用的是"/n",而被替換的內容中卻不能使用"/n",而只能使用"/r"。
3,去掉所有的"//"注釋:":%s!/ s*//.*!!"。首先可以注意到,這兒分隔符改用了"!",原因是在模式或字符串部分使用了"/"字符,不換用其他分隔符的話就得在每次使用"/"字符本身時寫成"//",上面的命令得寫成":%s//s*////.*//",可讀性較低。"."匹配表示除換行符之外的任何字符吧。
4,去掉所有的"/* */"注釋:":%s!/s*//*/_./{-}/*//s*! !g"。"/_."匹配包含換行在內的所有字符;"/{-}"表示前一個字符可出現零次或多次,但在整個正則表達式可以匹配成功的前提下,匹配的字符數越少越好;標志"g"表示一行裡可以匹配和替換多次。替換的結果是個空格的目的是保證像"int/* space not necessary around comments */main()"這樣的表達式在替換之後仍然是合法的。



正則總結(轉)



元字符 說明
. 匹配任意一個字符
[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個
/_. 匹配包含換行在內的所有字符
/{-} 表示前一個字符可出現零次或多次,但在整個正則表達式可以匹配成功的前提下,匹配的字符數越少越好
/= 匹配一個可有可無的項
/_s 匹配空格或斷行
/_[]

元字符 說明
/* 匹配 * 字符。
/. 匹配 . 字符。
// 匹配 / 字符。
// 匹配 / 字符。
/[ 匹配 [ 字符。

表示位置的符號
$ 匹配行尾
^ 匹配行首
/< 匹配單詞詞首
/> 匹配單詞詞尾

替換變量
在正規表達式中使用 /( 和 /) 符號括起正規表達式,即可在後面使用/1、/2等變量來訪問 /( 和 /) 中的內容。

懶惰模式
/{-n,m} 與/{n,m}一樣,盡可能少次數地重復
/{-} 匹配它前面的項一次或0次, 盡可能地少
/| "或"操作符
/& 並列

函數式
:s/替換字符串//=函數式
在函數式中可以使用 submatch(1)、submatch(2) 等來引用 /1、/2 等的內容,而submatch(0)可以引用匹配的整個內容。

與Perl正則表達式的區別 ?
元字符的區別
Vim語法 Perl語法 含義
/+ + 1-任意個
/? ? 0-1個
/{n,m} {n,m} n-m個
/(和/) (和) 分組
Copyright © Linux教程網 All Rights Reserved