linux學習筆記(實驗樓) 實驗13 正則表達式基礎

一、實驗介紹

 

1.1 實驗內容

雖然我們這一節的標題是正則表達式,但實際這一節實驗只是介紹grep,sed,awk這三個命令,而正則表達式作爲這三個命令的一種使用方式(正則表達式基本上是一種「表示法」,只要工具程序支持這種表示法,那麼該工具程序就可以用來作爲正則表達式的字符串處理之用,這三個命令便是)。正則表達式本身的內容很多,要把它說明清楚需要單獨一門課程來實現,不過我們這一節中涉及到的相關內容通常也能夠滿足很多情況下的需求了。

1.2 實驗知識點

  • 掌握基本命令:sed ,grep ,awk的用法

  • 掌握正則表達式符號和語法

 

 

二、正則表達式

 

什麼是正則表達式呢?

正則表達式,又稱正規表示式、正規表示法、正規表達式、規則表達式、常規表示法(英語:Regular Expression,在代碼中常簡寫爲 regex、regexp 或 RE),計算機科學的一個概念。正則表達式使用單個字符串來描述、匹配一系列符合某個句法規則的字符串。在很多文本編輯器裏,正則表達式通常被用來檢索、替換那些符合某個模式的文本。(簡單的說正則表達式就是處理字符串的方法,它是以行爲單位來進行字符串的處理行爲,正則表達式通過一些特殊符號的輔助,可以讓用戶輕易達到查找、刪除、替換某特定字符串的處理程序。)

許多程序設計語言都支持利用正則表達式進行字符串操作。例如,在 Perl 中就內建了一個功能強大的正則表達式引擎。正則表達式這個概念最初是由 UNIX 中的工具軟件(例如sed和grep)普及開的。正則表達式通常縮寫成「regex」,單數有 regexp、regex,複數有 regexps、regexes、regexen。

簡單的說形式和功能上正則表達式和我們前面講的通配符很像,不過它們之間又有很大差別,特別在於一些特殊的匹配字符的含義上,希望初學者注意不要將兩者弄混淆。(通配符代表的是bash操接口的一個功能,但正則表達式則是一種字符串處理的表示方式)

 

2.1 舉例

假設我們有這樣一個文本文件,包含"shiyanlou",和"shilouyan"這兩個字符串,同樣一個表達式:

如果這作爲一個正則表達式,它將只能匹配 shi,而如果不是作爲正則表達式*作爲一個通配符,則將同時匹配這兩個字符串。這是爲什麼呢?因爲在正則表達式中*表示匹配前面的子表達式(這裏就是它前面一個字符)零次或多次,比如它可以匹配"sh","shii","shish","shiishi"等等,而作爲通配符表示匹配通配符後面任意多個任意字符,所以它可以匹配"shiyanlou",和"shilouyan"兩個字符。

體驗完了,下面就來開始正式學習正則表達式吧。

 

2.2 正則表達式與shell在linux中的角色定位

我們在學習數學的時候,有一個很難但很重要的東西是一定要記住的,那就是九九乘法表,記住這個會使我們在以後學習數學的路上方便很多,這個乘法表在我們小學的時候幾乎花了一年時間才背下來,並不是那麼好背的,但它卻是基礎中的基礎。而我們今天學的正則表達式和前面的bash就有點像數學中的九九乘法表,是linux基礎中的基礎。

 

2.3 基本語法

一個正則表達式通常被稱爲一個模式(pattern),爲用來描述或者匹配一系列符合某個句法規則的字符串。

選擇

|豎直分隔符表示選擇,例如"boy|girl"可以匹配"boy"或者"girl"

數量限定

數量限定除了我們舉例用的*,還有+加號,?問號,如果在一個模式中不加數量限定符則表示出現一次且僅出現一次:

  • +表示前面的字符必須出現至少一次(1次或多次),例如,"goo+gle",可以匹配"gooogle","goooogle"等;

  • ?表示前面的字符最多出現一次(0次或1次),例如,"colou?r",可以匹配"color"或者"colour";

  • *星號代表前面的字符可以不出現,也可以出現一次或者多次(0次、或1次、或多次),例如,「0*42」可以匹配42、042、0042、00042等。

範圍和優先級

()圓括號可以用來定義模式字符串的範圍和優先級,這可以簡單的理解爲是否將括號內的模式串作爲一個整體。例如,"gr(a|e)y"等價於"gray|grey",(這裏體現了優先級,豎直分隔符用於選擇a或者e而不是gra和ey),"(grand)?father"匹配father和grandfather(這裏體驗了範圍,?將圓括號內容作爲一個整體匹配)。

語法(部分)

正則表達式有多種不同的風格,下面列舉一些常用的作爲 PCRE 子集的適用於perl和python編程語言及grep或egrep的正則表達式匹配規則:(由於markdown表格解析的問題,下面的豎直分隔符用全角字符代替,實際使用時請換回半角字符)

PCRE(Perl Compatible Regular Expressions中文含義:perl語言兼容正則表達式)是一個用 C 語言編寫的正則表達式函數庫,由菲利普.海澤(Philip Hazel)編寫。PCRE是一個輕量級的函數庫,比Boost 之類的正則表達式庫小得多。PCRE 十分易用,同時功能也很強大,性能超過了 POSIX 正則表達式庫和一些經典的正則表達式庫。

優先級

優先級爲從上到下從左到右,依次降低:

 

regex的思導圖:

 

 

三、grep模式匹配命令

 

上面空談了那麼多正則表達式的內容也並沒有提及具體該如何使用它,實在枯燥,如果說正則表達式是一門武功,那它也只能算得上一些口訣招式罷了,要把它真正練起來還得需要一些兵器在手才行,這裏我們要介紹的grep命令以及後面要講的sed,awk這些就該算作是這樣的兵器了。

 

3.1 基本操作

grep命令用於打印輸出文本中匹配的模式串,它使用正則表達式作爲模式匹配的條件。grep支持三種正則表達式引擎,分別用三個參數指定:

不過在你沒學過perl語言的大多數情況下你將只會使用到ERE和BRE,所以我們接下來的內容都不會討論到PCRE中特有的一些正則表達式語法(它們之間大部分內容是存在交集的,所以你不用擔心會遺漏多少重要內容)

在通過grep命令使用正則表達式之前,先介紹一下它的常用參數:

注:在大多數發行版中是默認設置了grep的顏色的,你可以通過參數指定或修改GREP_COLOR環境變量。

 

3.2使用正則表達式

使用基本正則表達式,BRE

  • 位置

查找/etc/group文件中以"shiyanlou"爲開頭的行

  • 數量

注意:其中\n爲換行符

  • 選擇

下面包含完整的特殊符號及說明:

注意:之所以要使用特殊符號,是因爲上面的[a-z]不是在所有情況下都管用,這還與主機當前的語系有關,即設置在LANG環境變量的值,zh_CN.UTF-8的話[a-z],即爲所有小寫字母,其它語系可能是大小寫交替的如,"a A b B...z Z",[a-z]中就可能包含大寫字母。所以在使用[a-z]時請確保當前語系的影響,使用[:lower:]則不會有這個問題。

注意:當^放到中括號內爲排除字符,否則表示行首。

使用擴展正則表達式,ERE

要通過grep使用擴展正則表達式需要加上-E參數,或使用egrep。

  • 數量

注意:推薦掌握{n,m}即可,+,?,*,這幾個不太直觀,且容易弄混淆。

  • 選擇

關於正則表達式和grep命令的內容就介紹這麼多,下面會介紹兩個更強大的工具sed和awk,但同樣也正是因爲這兩個工具的強大,我們的內容無法包含它們的全部,這裏將只對基本內容作介紹。

 

 

四、sed流編輯器

 

sed工具在 man 手冊裏面的全名爲"sed - stream editor for filtering and transforming text ",意即,用於過濾和轉換文本的流編輯器。

在 Linux/UNIX 的世界裏敢稱爲編輯器的工具,大都非等閒之輩,比如前面的"vi/vim(編輯器之神)","emacs(神的編輯器)","gedit"這些個編輯器。sed與上述的最大不同之處在於它是一個非交互式的編輯器,下面我們就開始介紹sed這個編輯器。

 

4.1 sed常用參數介紹

sed 命令基本格式:

 

4.2sed編輯器的執行命令(這裏「執行」解釋爲名詞)

sed執行命令格式:

其中n1,n2表示輸入內容的行號,它們之間爲,逗號則表示從n1到n2行,如果爲~波浪號則表示從n1開始以step爲步進的所有行;command爲執行動作,下面爲一些常用動作指令:

 

4.3 sed操作舉例

我們先找一個用於練習的文本文件:

打印指定行

行內替換

注意: 行內替換可以結合正則表達式使用。

行間替換

關於sed命令就介紹這麼多。

 

 

五、awk文本處理語言

 

看到上面的標題,你可能會感到驚異,難道我們這裏要學習的是一門「語言」麼,確切的說,我們是要在這裏學習awk文本處理語言,只是我們並不會在這裏學習到比較完整的關於awk的內容,還是因爲前面的原因,它太強大了,它的應用無處不在,我們無法在這裏以簡短的文字描述面面俱到,如果你有目標成爲一個linux系統管理員,確實想學好awk,你一不用擔心,實驗樓會在之後陸續上線linux系統管理員的學習路徑,裏面會有單獨的關於正則表達式,awk,sed等相關課程,敬請期待吧。下面的內容,我們就作爲一個關於awk的入門體驗章節吧,其中會介紹一些awk的常用操作。

 

5.1awk介紹

AWK是一種優良的文本處理工具,Linux及Unix環境中現有的功能最強大的數據處理引擎之一.其名稱得自於它的創始人Alfred Aho(阿爾佛雷德·艾侯)、Peter Jay Weinberger(彼得·溫伯格)和Brian Wilson Kernighan(布萊恩·柯林漢)姓氏的首個字母.AWK程序設計語言,三位創建者已將它正式定義爲「樣式掃描和處理語言」。它允許您創建簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。最簡單地說,AWK是一種用於處理文本的編程語言工具。

在大多數linux發行版上面,實際我們使用的是gawk(GNU awk,awk的GNU版本),在我們的環境中ubuntu上,默認提供的是mawk,不過我們通常可以直接使用awk命令(awk語言的解釋器),因爲系統已經爲我們創建好了awk指向mawk的符號鏈接。

nawk: 在 20 世紀 80 年代中期,對 awk語言進行了更新,並不同程度地使用一種稱爲 nawk(new awk) 的增強版本對其進行了替換。許多系統中仍然存在着舊的awk 解釋器,但通常將其安裝爲 oawk (old awk) 命令,而 nawk 解釋器則安裝爲主要的 awk 命令,也可以使用 nawk 命令。Dr. Kernighan 仍然在對 nawk 進行維護,與 gawk 一樣,它也是開放源代碼的,並且可以免費獲得; gawk: 是 GNU Project 的awk解釋器的開放源代碼實現。儘管早期的 GAWK 發行版是舊的 AWK 的替代程序,但不斷地對其進行了更新,以包含 NAWK 的特性; mawk 也是awk編程語言的一種解釋器,mawk遵循 POSIX 1003.2 (草案 11.3)定義的 AWK 語言,包含了一些沒有在AWK 手冊中提到的特色,同時 mawk 提供一小部分擴展,另外據說mawk是實現最快的awk

 

5.2 awk的一些基礎概念

awk所有的操作都是基於pattern(模式)—action(動作)對來完成的,如下面的形式:

你可以看到就如同很多編程語言一樣,它將所有的動作操作用一對{}花括號包圍起來。其中pattern通常是表示用於匹配輸入的文本的「關係式」或「正則表達式」,action則是表示匹配後將執行的動作。在一個完整awk操作中,這兩者可以只有其中一個,如果沒有pattern則默認匹配輸入的全部文本,如果沒有action則默認爲打印匹配內容到屏幕。

awk處理文本的方式,是將文本分割成一些「字段」,然後再對這些字段進行處理,默認情況下,awk以空格作爲一個字段的分割符,不過這不是固定的,你可以任意指定分隔符,下面將告訴你如何做到這一點。

 

5.3 awk命令基本格式

其中-F參數用於預先指定前面提到的字段分隔符(還有其他指定字段的方式) ,-v用於預先爲awk程序指定變量,-f參數用於指定awk命令要執行的程序文件,或者在不加-f參數的情況下直接將程序語句放在這裏,最後爲awk需要處理的文本輸入,且可以同時輸入多個文本文件。現在我們還是直接來具體體驗一下吧。

 

5.4 awk操作體驗

先用vim新建一個文本文檔

包含如下內容:

  • 使用awk將文本內容打印到終端

說明:在這個操作中我是省略了pattern,所以awk會默認匹配輸入文本的全部內容,然後在"{}"花括號中執行動作,即print打印所有匹配項,這裏是全部文本內容

  • 將test的第一行的每個字段單獨顯示爲一行

說明:你首先應該注意的是,這裏我使用了awk語言的分支選擇語句if,它的使用和很多高級語言如C/C++語言基本一致,如果你有這些語言的基礎,這裏將很好理解。另一個你需要注意的是NR與OFS,這兩個是awk內建的變量,NR表示當前讀入的記錄數,你可以簡單的理解爲當前處理的行數,OFS表示輸出時的字段分隔符,默認爲" "空格,如上圖所見,我們將字段分隔符設置爲\n換行符,所以第一行原本以空格爲字段分隔的內容就分別輸出到單獨一行了。然後是$N其中N爲相應的字段號,這也是awk的內建變量,它表示引用相應的字段,因爲我們這裏第一行只有三個字段,所以只引用到了$3。除此之外另一個這裏沒有出現的$0,它表示引用當前記錄(當前行)的全部內容。

  • 將test的第二行的以點爲分段的字段換成以空格爲分隔

說明:這裏的-F參數,前面已經介紹過,它是用來預先指定待處理記錄的字段分隔符。我們需要注意的是除了指定OFS我們還可以在print 語句中直接打印特殊符號如這裏的\t,print打印的非變量內容都需要用""一對引號包圍起來。上面另一個版本,展示了實現預先指定變量分隔符的另一種方式,即使用BEGIN,就這個表達式指示了,其後的動作將在所有動作之前執行,這裏是FS賦值了新的"."點號代替默認的" "空格

注意:首先說明一點,我們在學習和使用awk的時候應該儘可能將其作爲一門程序語言來理解,這樣將會使你學習起來更容易,所以初學階段在練習awk時應該儘量按照我那樣的方式分多行按照一般程序語言的換行和縮進來輸入,而不是全部寫到一行(當然這在你熟練了之後是沒有任何問題的)。

 

5.5 awk常用的內置變量

關於awk的內容本課程將只會包含這些內容。

 

 

挑戰:數據提取

介紹

小明在做數據分析的時候需要提取文件中關於數字的部分,同時還要提取用戶的郵箱部分,但是有的行不是數組也不是郵箱,現在需要你在 data2 這個文件中幫助他用正則表達式匹配出數字部分和郵箱部分。

數據文件可以使用以下命令下載:

下載後的數據文件路徑爲 /home/shiyanlou/data2。

目標

  1. 在文件 /home/shiyanlou/data2 中匹配數字開頭的行,將所有以數字開頭的行都寫入 /home/shiyanlou/num 文件。

  2. 在文件 /home/shiyanlou/data2 中匹配出正確格式的郵箱,將所有的郵箱寫入 /home/shiyanlou/mail 文件,注意該文件中每行爲一個郵箱。

提示

  1. 郵箱的格式匹配

  2. 注意符號 . 的處理

來源

2016 年 TapFun 校招面試題

參考答案

注意:請務必自己獨立思考解決問題之後再對照參考答案,一開始直接看參考答案收穫不大。