? grep號稱文本處理三劍客之一,雖然說是三劍客中功能最少也是最簡單的,但仍然不能小覷。
? grep的全稱為:Global search REgular expression and Print out the line,即:全面查找正則表達式并將匹配的行顯示出來。
? 那么這里面出現了一個新的概念:正則表達式。那么什么是正則表達式呢?
? 正則表達式,又稱正規表示法、常規表示法英語:(Regular Expression,在代碼中常簡寫為regex、regexp或RE),計算機科學的一個概念。正則表達式使用單個字符串來描述、匹配一系列符合某個句法規則。在很多文本編輯器里,正則表達式通常被用來檢索、替換那些符合某個模式的文本。
? 正則表達式是對字符串操作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個"規則字符串",這個"規則字符串"用來表達對字符串的一種過濾邏輯。
? 給定一個正則表達式和另一個字符串,我們可以達到如下的目的:
??? 1.給定的字符串是否符合正則表達式的過濾邏輯(稱作“匹配”);
??? 2.可以通過正則表達式,從字符串中獲取我們想要的特定部分。
? 正則表達式的特點是:
??? 1.靈活性、邏輯性和功能性都非常的強;
??? 2.可以迅速地用極簡單的方式達到字符串的復雜控制。
??? 3.對于剛接觸的人來說,比較晦澀難懂。
? 由于正則表達式主要應用對象是文本,因此它在各種文本編輯器場合都有應用。許多程序設計語言都支持利用正則表達式進行字符串操作。例如,在Perl中就內建了一個功能強大的正則表達式引擎——PCRE;此外,還有java語言自帶的。
? 主流的正則引擎又為3類:一、DFA,二、傳統型NFA,三、POSIX NFA。
? DFA 引擎在線性時狀態下執行,因為它們不要求回溯(并因此它們永遠不測試相同的字符兩次)。DFA引擎還可以確保匹配最長的可能的字符串。但是,因為DFA引擎只包含有限的狀態,所以它不能匹配具有反向引用的模式;并且因為它不構造顯示擴展,所以它不可以捕獲子表達式。
? 傳統的NFA引擎運行所謂的“貪婪的”匹配回溯算法,以指定順序測試正則表達式的所有可能的擴展并接受第一個匹配項。因為傳統的 NFA構造正則表達式的特定擴展以獲得成功的匹配,所以它可以捕獲子表達式匹配和匹配的反向引用。但是,因為傳統的NFA回溯,所以它可以訪問完全相同的狀態多次(如果通過不同的路徑到達該狀態)。因此,在最壞情況下,它的執行速度可能非常慢。因為傳統的NFA接受它找到的第一個匹配,所以它還可能會導致其他(可能更長)匹配未被發現。
? POSIX NFA引擎與傳統的NFA引擎類似,不同的一點在于:在它們可以確保已找到了可能的最長的匹配之前,它們將繼續回溯。因此,POSIX NFA引擎的速度慢于傳統的NFA引擎;并且在使用POSIX NFA時,您恐怕不會愿意在更改回溯搜索的順序的情況下來支持較短的匹配搜索,而非較長的匹配搜索。
? 使用DFA引擎的程序主要有:awk, egrep, flex, lex, MySQL, Procmail等;
? 使用傳統型NFA引擎的程序主要有:GNU Emacs, Java, ergp, less, more, .NET語言, PCRE library, Perl, PHP, Python, Ruby, sed, vi, vim;
? 使用POSIX NFA引擎的程序主要有:mawk, Mortice Kern Systems’ utilities, GNU Emacs(使用時可以明確指定);
? 也有使用DFA/NFA混合的引擎:GNU awk, GNU grep/egrep, Tcl。
? 有了上述的一點知識,接下來繼續跟大家一起來討論grep就簡單些了。為了能夠滿足不同用戶的不同需求,grep家族中已經有了三個成員,即:grep、egrep、fgrep。其中grep是最基本的一個功能實現,如果想要更加簡單的使用擴展的正則表達式,使用egrep就可以了;如果想要快速實現查找而不需要使用正則表達式的匹配的話,就要選擇fgrep了。
? 不管使用哪個命令,我們的目的都是唯一的:正確的從指定文件中查找得到我們感興趣的那些行。
下面介紹以下grep命令的使用方法:
grep:外部命令
? 功能:從源數據中顯示出被模式匹配到的行。而且,grep默認工作在貪婪模式下,也就是說,每次grep進行模式匹配都是按照盡可能多的去完成匹配的標準進行的。
? 格式:
?? ?grep [OPTIONS] PATTERN [FILE...]
?? ?grep [OPTIONS] [-e PATTERN | -f FILE] [FILE...]
? 常用選項:
??? -A NUM, --after-context=NUM:被模式匹配到的行以及其后#行,如果后面沒有,則不顯示;不能和-o選項一同使用
??? -B NUM, --before-context=NUM: 被模式匹配到的行以及其前#行,如果前面沒有,則不顯示;不能和-o選項一同使用
??? -C NUM, -NUM, --context=NUM:被模式匹配到的行以及其前后各#行,如果前面或后面沒有,則不顯示;不能和-o選項一同使用
??? --color=auto: 對匹配到的文本著色顯示;
??? -e PATTERN, --regexp=PATTERN:實現以邏輯或的關系完成多個模式的匹配,每個-e選項只能帶一個模式作為參數
??? -E, --extended-regexp:擴展正則表達式開關,能夠讓grep使用正則表達式
??? -i, --ignore-case: 忽略字符大小寫
??? -n, --line-number:顯示匹配的行在原文件中的行號
??? -o, --only-matching: 僅顯示匹配到的字符串;
??? -q, --quiet, --silent: 靜默模式,不輸出任何信息;
??? -v, --invert-match: 顯示那些沒有被模式匹配到的行;
??? -w, --word-regexp:整行匹配整個單詞
? 退出狀態:
??? 如果成功查找到被選中的行,狀態返回值為0;否則就是1
??? 如果發生了錯誤,而且沒有加-q、--quiet或--silent選項,則狀態返回值為2
?? ?
? PATTERN也可稱為模式,可以有很多種構成方式:
??? 1.普通的字符或字符串
??? 2.正則表達式(元字符)
??? 例如:
?? ?[root@localhost ~]# grep 'root' /etc/passwd
?? ?root:x:0:0:root:/root:/bin/bash
?? ?operator:x:11:0:operator:/root:/sbin/nologin
?? ?此例中用于給grep提供匹配條件的PATTERN即為字符串。這樣的PATTERN在匹配的時候非常機械,不靈活,所以作用并不明顯。
? 下面針對于常用的基本正則表達式的元字符進行了一個簡單的歸類,希望對大家能有所幫助:
??? 1.通配符:
????? .(點) :通用匹配任意單個字符
????? []:通用匹配任意指定范圍內的單個字符
????? ^ :用在中括號中,對中括號中通配的字符取反,即表示"不包括"的意思.
????? 除此之外,GLOB所提供的通配字符集也是可以在正則表達式中被使用的。下面也列出了常用的幾種:
????? [:digit:]:表示所有的十進制數字,相當于0-9
????? [:upper:]:表示所有的大寫英文字母,相當于A,B,C,D,...,X,Y,Z
????? [:lower:]:表示所有的小寫英文字母,相當于a,b,c,d,...,x,y,z
????? [:alpha:]:表示所有的英文字母,包括大寫和小寫,即上兩個字符集合的并集。
????? [:alnum:]:表示所有的英文字母,包括大寫和小寫字母,還包括所有的十進制數字,前三個字符集合的并集
????? [:space:]:表示所有的空白字符。
????? [:punct:]:表示所有的特殊符號,包括,./!?\;'"-=+_等
????? [^[:punct:]]:表示任意一個所有的非特殊符號的字符。
??? 2.前面字符出現次數:
????? *:其前面的字符可以出現0次或任意次,相當于:\{0,\}
????? \?:其前面的字符可以出現0次或1次,相當于:\{0,1\}
????? \+:其前面的字符至少出現1次,相當于:\{1,\}
????? \{\}:其前面的字符可以出現任意指定的次數
??????? \{m\}:其前面的字符必須出現m次
??????? \{0,m\}:其前面的字符可以出現0次或最多m次
??????? \{m,\}:其前面的字符至少出現m次
??????? \{m,n\}:其前面的字符至少出現m次,最多出現n次
??? 3.錨定字符:
????? ^ :行首錨定字符
????? $ :行尾錨定字符
????? \<:詞首錨定字符
????? \>:詞尾錨定字符
??? 4.分組字符:
????? \(\):將括于括號中的字符分為一組
????? 在正在表達式處理引擎中,如果一旦發現小括號,就按照括號出現的順序,將對應位置的括號里面的內容記錄到某個特定的變量中,而調用這些變量中存儲數值的方法,叫做"后向引用",也就是使用\1, \2, \3, ...等
??? 5.選擇字符:
??? \|:或者,表示或者符號左右的整體是可選的內容
????? 如:b\|root,表示b或者root兩種情況
????????? \(b\|r\)oot則表示boot或root兩種情況,后者是使用\(\)分組的結果。
??? 注意:使用正則表達式元字符的時候,一定要注意以下幾點:
????? 1.正則表達式是由正則表達式的元字符構成的,在構成正則表達式的時候,各個元字符之間一般沒有空白字符。
????? 2.最好是在引號中使用正則表達式的元字符,否則可能會被shell解釋而不是被正則表達式引擎處理了。
????? 3.在書寫引號的時候,單引號和雙引號都可以,但是要考慮到$字符的使用,一旦有$用來表示行尾,則必須使用單引號,否則將會被shell解釋為變量引導符,從而企圖將其后面的字符串理解成變量名,從而取到控制,而干擾了我們的使用
????? 4.如果想要使用字符本身,比如".",則需要在這個元字符前面加"\"即可,如"."表示任意單個字符,而'\.'則僅僅只是表示.這個字符本身,有的時候,我們可能要匹配域名或者IP地址,則必須用這個方法才可以。
????? 5.在我們書寫正則表達式的時候,應該盡可能周密的思考問題,盡可能把各種情況都考慮進來,從而才能寫出最符合要求的正則表達式。 ?
? 擴展的正則表達式的元字符:
??? 包括了所有的基本正則表達式的元字符,同時有了新的規定:
????? \? --> ?
????? \{\} --> {}
????? \(\) --> ()
? ? ? \+ --> +
????? \| --> |
????? 詞首錨定和詞尾錨定中的"\"依然被保留。
下面我們來做幾個例子,以方便大家的理解。
1.取出/etc/sysconfig/network-scripts/ifcfg-eno16777736這個文件的基名
[root@localhost?~]#?echo?/etc/sysconfig/network-scripts/ifcfg-eth0?|?grep?-o?"[^\/]\+\/\?$"?|?tr?-d?'/' ifcfg-eth0
2.找出/etc/rc.d/init.d/functions文件中某單詞(包括下劃線)后面跟一個小括號的行
[root@localhost?~]#?grep?-o?".*_*.*()"?/etc/init.d/functions systemctl_redirect?() checkpid() __pids_var_run() __pids_pidof() daemon() killproc() pidfileofproc() pidofproc() status() echo_success() echo_failure() echo_passed() echo_warning() update_boot_stage() success() failure() passed() warning() action() strstr() is_ignored_file() is_true() is_false() apply_sysctl()
3.顯示/etc/passwd文件中用戶名與該用戶的默認shell名相同的用戶賬戶信息
[root@localhost?~]#?grep?-E?"(\<.+\>).*\1$"?/etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt
4.顯示利用ldd命令查看到的ls命令所使用的動態庫文件的絕對路徑
[root@localhost?~]#?ldd?/bin/ls?|?egrep?-o?"/.*lib(64)?/[^[:space:]]+" /lib64/libselinux.so.1 /lib64/libcap.so.2 /lib64/libacl.so.1 /lib64/libc.so.6 /lib64/libpcre.so.1 /lib64/liblzma.so.5 /lib64/libdl.so.2 /lib64/ld-linux-x86-64.so.2 /lib64/libattr.so.1 /lib64/libpthread.so.0
5.grep還可以從多個文件中查找匹配字符,如:
[root@localhost?test]#?ls fstab??inittab??issue [root@localhost?test]#?grep?'ro'?./* ./fstab:proc???/proc????proc????defaults????????0?0 ./inittab:#?Ctrl-Alt-Delete?is?handled?by?/etc/init/control-alt-delete.conf
轉載于:https://blog.51cto.com/zhaotianyu/1775956