正則表達式

正則表達式

熱身

正則表達式(regular expression)描述了一種字符串匹配的模式,可以用來檢查一個串是否含有某種子串、將匹配的子串做替換或者從某個串中取出符合某個條件的子串等。

例如 grep, expr, sed , awk. 或Vi中經常會使用到正則表達式,為了充分發揮 shell 編程的威力

 

下面先舉個簡單例子來讓大家對正則表達式有個直觀的感受。ls命令是linux下最常用的命令。ls命令是list的縮寫,缺省下ls用來打印出當前目錄的清單。

正則表達式

現在,我們只希望列出以d開頭的文件或目錄,可以用ls d* 命令,這里*是通配符,它表示匹配重復零次或多次前一字符。

正則表達式

舉一反三,列出以che 開頭的文件或目錄,就可以用ls che* 命令。

是不是覺得有些覺得過于簡單了?。??!!好吧,打完小怪,現在升下級。

開始……

如何列出當前目錄下的所有目錄(不包含下面的子目錄)

思考……

到了使出正則表達式殺手锏的時候了,在這里,我們還是使用ls 命令,但是加了個 -l選項(-l選項作用是列出文件的詳細信息),使用正則表達式列出當前目錄下的所有目錄,我們給出了兩種方法(聰明的你當然會想到也可以用find命令,呵呵,這屬于第三種秘笈了)。且看:

正則表達式

這樣列出來的內容有些多,沒完全截下來所有顯示結果,但這并不妨礙本文的講解。

考慮到普通文件是以-開頭,如dataf1.txt文件;目錄是以開頭的,如 adv_shell 是目錄,即第一個字母會不小心暴露出文件的身份屬性。

正則表達式

所以我們就從d這里作為突破口,這時,你會想到,有多少個“開頭”的d就應該有多少個目錄,太聰明了,好吧,我們按照你的思路實踐下。

現在,問題出來了,怎么統計出來有多少個“開頭”的d?你想到了linuxgrep命令,還想到了正則表達式,于是grep正則表達式開始粉墨登場了……

正則表達式

ls -l |grep "^d"

這條簡單的命令就輕松解決了我們的問題,。"^d"???你納悶了,這個小東西配合起來怎么會有那么大的威力呢?這好比玩三國殺時劉備、司馬懿、香香之間配合的威力……"^d",就是正則表達式的用法,"^"表示匹配行首,"^d"合起來就表示以d開頭的一行,grep "^d" 就是過濾出以d開頭的那些行,表示目錄,也就過濾出了當前目錄中的所有目錄。

謎底解開?,F在你又想到,前面不是說還有一種方法的么,既然如此迫不及待,那就只好順水推舟了。

第二種方法還是基于ls命令,但是用了-F 選項,-F 選項能列出文件類型的指示符號,如下圖所示:

正則表達式

仔細觀察我們發現,在文件名后面,會多出了一些符號,如目錄adv_shell名字后多了條斜扛(/),可執行文件checkhost.sh名字后多了個星號(*)……在此,如果想更多了解這些符號意義,可以查看ls 命令的詳細信息。

我們現在把注意力集中到目錄adv_shell名字后多了條斜扛(/)這條信息上。很快聯想到,有多少個斜扛(/)就應該對應多少目錄,而且斜扛(/)會跟在每個目錄名的最后。我們又想到了grep命令,還想到了應該怎樣用正則表達式表示出匹配行尾,答案已經很接近了……

正則表達式

ls -F | grep "/$" 

這條短命令又一切成全了我們的夢想。"/$" 也是正則表達式的用法,"$"表示匹配行尾,"/$"合起來就表示匹配以/結尾的行,grep "/$" 就是過濾出以/結尾的那些行,/表示目錄,也就過濾出了當前目錄中的所有目錄。

在此基礎上,我們發散一下思維,比如說想統計當前目錄下的文件個數及目錄個數,就可以使用以下命令:

ls -l * |grep "^-"|wc -l 

ls -l * |grep "^d"|wc -l 

好了,暫且休息,下面我們開始介紹更多關于正則表達式的知識

前面我們初識了^ $ * 這些個正則表達式的用法,下面我們將進行更高一級的升煉。

正則表達式是一個字符或和元字符組合成的字符集,它們匹配(或指定)一個模式。字符即普通字符(例如字符 到 z),元字符即特殊字符(例如前面提到的字符 ^ $ *)。正則表達式作為一個模板,將某個字符模式與所搜索的字符串進行匹配。

在這里,為簡單見,我們不會介紹所有的正則表達式知識,只介紹常用的一些正則表達式知識。

一個正則表達式包含下面一個或多個項:

1.一個字符集

這里的字符集里的字符表示的就是它們字面上的意思.正則表達式最簡單的情況就是僅僅由字符集組成,而沒有其他的元字符。

2.

一個錨指明了正則表達式在一行文本中要匹配的位置,例如^$就是錨。

3.修飾符

它們用于展開或縮小(即是修改了)正則表達式匹配文本行的范圍.修飾符包括了星號、括號和反斜杠符號。

* 匹配重復零次或多次前一字符 

+ 匹配一個或多個前面的字符.它的作用和*很相似,但唯一的區別是它不匹配零個字 符的情況

? 匹配零或一個前面的字符。它一般用于匹配單個字符 

. 匹配任意字符( 除換行符 

^ 匹配一行的開頭,但依賴于上下文環境,可能在正則表達式中表示否定一個字符 集的意思
[…] 匹配集合中任意字符 如"[xyz]" 匹配字符 x, y, z
[^…] 匹配不屬集合 中 任意字符 
^, $ 匹配 行首、行尾 
\<, \> 用于表示單詞的邊界。\< 匹配詞首,\>詞尾,如"\<the\>" 匹配單詞"the"
... 正則表達式分組。進行子字符串提取(substring extraction)一起使用很有用
\n 第 n 個分組內容  

\ 轉義(escapes) 一個特殊的字符,使這個字符表示原來字面上的意思。"\$"表示 了原來的字面意思"$",而不是在正則表達式中表達的匹配行尾的意思."\\"也被 解釋成了字面上的意思"\"

\{ \} 指示前面正則表達式匹配的次數. 

要轉義是因為不轉義的話大括號只是表示他們字面上的意思.這個用法只是技巧上 的而不是基本正則表達式的內容."[0-9]\{5\}" 精確匹配5個數字(09的數字). 

| "",正則操作符用于匹配一組可選的字符

{n} n是一個非負整數。匹配確定的n次。例如,''o{2}'' 不能匹配 "Bob"中的''o'',但是能匹配"food" 中的兩個o。

{n,} n是一個非負整數。至少匹配n次。例如,''o{2,}'' 不能匹配"Bob"中的'o'',但能匹配 "foooood"中的所有o。''o{1,}''等價于''o+''。''o{0,}''則等價于''o*''。

{n,m} mn均為非負整數,其中n<=m。最少匹配n次且最多匹配m次。例如,"o{1,3}"將匹配 "fooooood"中的前三個o。''o{0,1}''等價于''o?''。請注意在逗號和兩個數之間不能有空格。

\b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如,''er\b'' 可以匹配"never" 中的''er'',但不能匹配 "verb"中的 ''er''。 

\B 匹配非單詞邊界。''er\B''能匹配"verb"中的''er'',但不能匹配"never"中的 ''er''

\w 匹配包括下劃線的任何單詞字符。等價于''[A-Za-z0-9_]''。

\W 匹配任何非單詞字符。等價于''[^A-Za-z0-9_]''。

\d 匹配一個數字字符。等價于[0-9]。

\D 匹配一個非數字字符。等價于[^0-9]。

\f 匹配一個換頁符。等價于\x0c\cL。

\n 匹配一個換行符。等價于\x0a\cJ。

\r 匹配一個回車符。等價于\x0d\cM。

\s 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于[\f\n\r\t\v]。

\S 匹配任何非空白字符。等價于[^\f\n\r\t\v]。

\t 匹配一個制表符。等價于\x09 和 \cI。

\v 匹配一個垂直制表符。等價于\x0b\cK。

分例子 

/\b([a-z]+)\1\b/gi 一個單詞連續出現的位置 

/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/ 將一個URL解析為協議、域、端口及相對路徑

/^(?:Chapter|Section) [1-9][0-9]{0,1}$/定位章節的位置 

/[-a-z]/ Az26個字母再加一個號。

/ter\b/ 可匹配chapter,而不能terminal

/\Bapt/ 可匹配chapter,而不能aptitude

/Windows(?=95 |98 |NT )/ 可匹配Windows95Windows98WindowsNT,當找到一個匹配后,從Windows后面開始進行下一次的檢索匹配。

下面來些更加高級些的例子。

對于vi 中命令的分析

s/.?$\n^.*$/\1/g

初一看,會傻眼,眼前感覺全是$^.*/\……這些符號的閃動。

不要緊,下面慢慢道來。

先給出vi中替換命令的格式。

s/re/string  用string替換正則表達式re

如果在后面加了個g 如: s/re/string/g

表示表示對該行內符合模式的進行全部替換。

例如,s/\//_/g 這個正則表達式就表示,對行內所有的斜扛(/)替成下劃線(_),\ /即替換命令格式中的re,用反斜扛\是為了轉義,\ /即表示 的本意;_即替換命令格式中的string。

好了,了解vi中替換命令的格式后,我們再對細節進行分析。

前面介紹到 ... 表示正則表達式分組,\n表示第 個分組內容,于是對于

s/.?$\n^.*$/\1/g 

中的 \1 ,就表示第一個正則表達式分組即.?$,我們暫將第一個正則表達式分組.?$其記為:A

類推,\2就應該表示第二個正則表達式分組,即 \n^.*$  實際上 也應該寫在括號內比較好:\n.?$ ,我們也暫將第二個正則表達式分組 \n^.*$ 記為:B

好了,

%s/.?$\n^.*$/\1/g

就可以寫為:

s/AB/A/g

作用就是將行內所有的AB都替換成A。

現在我們來分別分析AB的作用。

A=.?$

抽取出來實際上是...,表示正則表達式 分組,再分析括號內的^.*$,^代表行首,點號(.)匹配任意字符(除換行符),星號(*)匹配重復零次或多次前一字符,$代表匹配到行尾,綜合起來就是:匹配這一行

B=\n^.*$

分析: \n換行,^.*$同上,表示匹配這一行,綜合起來就是:下一行(即上行結束后開始的另一行)。

再于是就有:%s/AB/A/g 即將所有AB都替換成B  ,代入AB各自意思得到:

將兩行(如行1和行)內容替換為第一行內容(即行1的內容),加上/g,就是對全文進行前述替換,也就是隔行刪除,如果是從文件第一行開始進行的操作,就意味著是刪除所有偶數行、保留所有奇數行操作。

從上面的分析過程中,我們總結出兩條有用的正則表達式:

%s/.?$\n^.*$/\1/g 刪除偶數行

%s/^.*$\n.?$/\1/g 刪除奇數行

不過癮的話,還可以再看看另一例子:

sed 's/.?.$/\2/'

\2就應該表示第二個正則表達式分組

同上,也將A=/.?,B=.$,表達式變為's/AB/B',將AB都替換成。

分析A、B作用。

A=/.?

抽取出來實際上是...,表示正則表達式 分組,再分析括號內的 .*,表示匹配任意零個或多個字符 除換行符 

B=.$

括號內的 . ,表示匹配任意字符(除換行符) ,括號外的$表示匹配到行尾,即表示行尾的最后一個字符;那上述的A /.?  就表示該行最后一個字符前的所有字符。

于是sed 's/.?.$/\2/' 作用就是:刪除該行除最后一個字符外的所有字符,保留最后一個字符,也即取得該行最后一個字符。

好了,正則表達式的介紹就告一段落,知識點比較多,需要平時反復的積累,遇到復雜的正則表達式時首先要克服恐懼的心理,然后按照上面的方法化繁為簡,抓住其本質的東西,有如探囊取物,必手到擒來。

原創文章,作者:NddTx99521,如若轉載,請注明出處:http://www.www58058.com/33311

(0)
NddTx99521NddTx99521
上一篇 2016-08-12
下一篇 2016-08-12

相關推薦

  • shell進階之循環

    循環執行,將某代碼段重復運行多次

    重復運行多少次:

    循環次數事先已知

    循環次數事先未知

    有進入條件和退出條件

    for, while, until

    Linux干貨 2017-12-24
  • LVS詳解

    概述     LVS是工作在4層的負載均衡調度器,可根據請求報文的目標IP和目標協議及端口,根據指定的調度算法,將請求調度轉發至某RealServer,本篇就針對LVS的原理,配置和使用進行簡單介紹,具體包含:     1、LVS的四種類型的介紹   &nbs…

    Linux干貨 2016-10-27
  • 軟鏈接和硬鏈接詳解

    軟連接和硬鏈接圖解 硬鏈接 符號鏈接 軟鏈接和硬鏈接詳解 軟鏈接和硬鏈接詳解 Linux下的鏈接文件有點類似于Windows的快捷方式,但又不完全一樣。鏈接文件有兩種:一種是硬鏈接,另一種是符號鏈接(又稱軟鏈接)。 UNIX文件系統提供了一種將不同文件鏈接至同一個文件的機制,我們稱這種機制為鏈接。它可以使得單個程序對同一文件使用不同的名字。這樣的好處是文件系…

    Linux干貨 2016-09-06
  • VMware vSphere所需要開放的端口

        80 vCenter Server需要端口80用于直接HTTP連接。端口80會將請求重定向到HTTPS端口443。如果意外使用了http://server而不是https://server,此端口將非常有用。     389 此端口在vCenter Server的本地和所…

    Linux干貨 2016-07-07
  • vim文本編輯器練習

    1、復制/etc/profile至/tmp/目錄,用查找替換命令刪除/tmp/profile文件中的行首的空白字符? :%s@^[[:space:]]\+@@gc   2、復制/etc/rc.d/init.d/functions文件至/tmp目錄,用查找替換命令為/tmp/functions的每行開頭為空白字符的行的行首添加一個#號? :%s@^[…

    Linux干貨 2016-08-12
  • rpm詳解

    rpm詳解 rpm詳解 rpm使用方法 rpm起源 rpm是什么 rpm命名格式 rpm優缺點 rpm獲取注意 rpm命令使用 rpm起源  由于在linux中安裝應用程序需要源碼包編譯安裝,對于非專業人員而言難度太大,因而出現一種將源碼編譯好的二進制程序,庫文件,配置文件,幫助文件等打包成一個或多個特定格式的程序包,而管理這類包的工具之一,則稱為…

    Linux干貨 2016-12-23
欧美性久久久久