sed、grep


        兩個概念,通配符與正則表達式,這兩個規範的實現都是由軟件所提供的,如通配符:shell和find,而它們的實現之間還有區別如:shell的[ ]裏面是不區分大小寫的。而find是區分大小寫的。linux

而正則表達式這一種更爲強大的搜索規範所使用的軟件如:vi,sed,grep,awk。
git


Linux上文本處理三劍客:
grep, egrep, fgrep:文本過濾工具(模式:pattern)工具;
    grep:基本正則表達式,-E (egrep),-F(fgrep)
    egrep:擴展正則表達式, -G(grep),-F(fgrep)
    fgrep:不支持正則表達式,性能更好。
正則表達式

sed:stream editor, 流編輯器;文本編輯工具;
awk:Linux上的實現爲gawk,文本報告生成器(格式化文本);shell

使用:http://fanqie.blog.51cto.com/9382669/1650244express


正則表達式:Regual Expression, REGEXP
由一類特殊字符(元字符)及文本字符所編寫的模式,這些元字符不表示其字面意義,而是用於表示控制或通配的功能.
分兩類:
基本正則表達式:BRE
擴展正則表達式:ERE

緩存

目錄:bash

1、grepapp

一、正則表達式ssh

二、擴展正則表達式tcp

2、sed


1、grep

grep: Global search REgular expression and Print out the line.
做用:文本搜索工具,根據用戶指定的「模式(過濾條件)」對目標文本逐行進行匹配檢查;打印匹配到的行;
模式:由正則表達式的元字符及文本字符所編寫出的過濾條件;
正則表達式引擎;

grep  [OPTIONS]  PATTERN  [FILE...]
grep  [OPTIONS]  [-e PATTERN | -f FILE]  [FILE...]

    OPTIONS:
        --color=auto:對匹配到的文本着色後高亮顯示;
        -i:ignorecase,忽略字符的大小寫;
        -o:僅顯示匹配到的字符串自己;
        -v, --invert-match:顯示不能被模式匹配到的行;
        -E:支持使用擴展的正則表達式元字符;
        -q, --quiet, --silent:靜默模式,即不輸出任何信息;
        
        -A #:after, 後#行
        -B #:before,前#行
        -C #:context,先後各#行
        
一、基本正則表達式

字符匹配: 

. 點號匹配任意單個字符。
[] 匹配裏面的任意單個字符,如:[acdb]  a,c,d,b,這四個單字符都會匹配
[^] 不匹配裏面的任意單個字符。跟上面徹底相反,這四個單字符都不會匹配。

上面的[ ]之間也能夠用下面這些字符組。它們表明一部分字符的組合。

[:upper:]  大寫字母

[:lower:]  小寫字母

[:alpha:]  全部字母

[:digit:]  全部數字

[:alnum:]  全部字母和數字

[:space:]  空格

[:punct:]  標點符號


如:查找大寫字母[[:upper:]]。裏面的[:upper:]是一個總體,與外面的[ ]沒有關係,因此不能省略。



次數匹配:用在要指定其出現的次數的字符的後面,用於限制其前面字符出現的次數;默認工做於貪婪模式;

* 任意次前面的字符。包括0次。如:s*    沒有s的也會匹配。
.* 只是一種應用方法,表明任意個任意字符。
\? 前面字符的0次或1次。
\{m\} 前面字符的m次。手動指定前面字符的次數。
\{m,n\} 前面的字符的m-n次。如:\{2,3\}  2-8次前面的字符。
\{m,\} 前面的字符至少m次。沒有上限,只有下限。
\{0,n\} 前面的字符至多隻有n次。也就是從0到n個。
\+ 前面的字符等於大於1次,與*相比,沒有0次了。

             

位置錨定:用於指定字符出現的位置。

^ 指定行首
$ 指定行尾
^$ 這個只是一種應用方法, 表明空白行。 行首跟着行尾  空白行。
\<char 查找以字符開頭的單詞。 用 \b 也行。   \bchar    char是字符的意思。
char\> 查找以字符結尾的單詞。 用\b 也行。   char\b



\(\)

用於把單個字符組合成多個字符, 以組的方式再來次數匹配。 並且能夠被引用。

組的功能:一、把多個字符組合成總體來作次數匹配。二、能夠後向引用

\# 後向引用。#爲數字,能夠引用第#個組的匹配結果,也就是第#個小括號。注意引用的是組所匹配到的結果,而不是把組的功能給複製過來。
\|

或。如:"^abc|^def", 開頭是abc,或者開頭是def的。也能夠"^\(abc\|def\)"

分組括號中的模式匹配 到的內容會被正則表達式引擎自動記錄於內部的變量中,這些變量爲:
           \1:模式從左側起,第一個左括號以及與之匹配的右括號之間的模式所匹配到的字符;
           \2:模式從左側起,第二個左括號以及與之匹配的右括號之間的模式所匹配到的字符;

             ...

關於後向引用。老師上課的時候,所給出的頗有意思的題。

找出先後同樣的love或者like。就是前是love後面就要是love.

                    He loves his lover.
                    He likes his lover.
                    She likes her liker.
                    She loves her liker.

                    ~]# grep  "\(l..e\).*\1"  lovers.txt

wKiom1aEpQbAigIIAAAfrErHcyA050.jpg



、查找下以 f 開頭,中間兩個任意字符,以 m 結尾的都有哪些。

[root@star-linux ~]# grep "f..m" text.tx
But from behind the walls of doubt
[root@star-linux ~]# 


、 第一個字符要麼是g 要麼是m,中間是兩個同樣的,結尾一個d,怎麼查  [ ]   \{m\}

[root@star-linux ~]# grep  "[gm].\{2\}d" text.tx

good morning everyone
I had a dream, I had an awesome dream
As we go down life's lonesome highway
[root@star-linux ~]# 


結果出乎意料, 這是由於 . 是任意字符, 而\{2\} 是表明2個前面的字符,也就是兩個任意字符了(包括空格),這個題作的有問題。在要求先後同樣的狀況下,就要用到後向引用了。



、用組和後向引用。\(\)    \# 後向引用

[root@star-linux ~]# grep  "[gm]\(.\)\1d" text.tx
good morning everyone
[root@star-linux ~]#


咱們要的是這個結果。 上面的意思就是小括號裏面的 . 所匹配到的是什麼結果,後面\1也就是什麼結果, 在個例子中,小括號是 o , 那麼 \1 也就是 o.


、查找下行開頭是A 或者 As 。 ^   \?

[root@star-linux ~]# grep "^As\?" text.tx
And what they played
A voice was crying out
As we go down life's lonesome highway
[root@star-linux ~]# 


、再查找個單詞試試,way , 找這個單詞,那咱們就來試試。

[root@star-linux ~]# grep "way" text.tx
Say it for always
That's the way it should be
Say it for always
That's the way it should be

Say it for always            

.........
[root@star-linux ~]# 


What? 搞什麼仙人闆闆,把有關way的字符串都給拉出來了。 那麼  \<  \> 


[root@star-linux ~]# grep "\<way\>" text.tx
That's the way it should be
That's the way it should be
When you feel you've lost your way
That's the way it should be
That's the way it should be
[root@star-linux ~]# 


\<  \> 指定單詞用的,這兩個符號的兩邊只容許出現空格或者標點符號。若是是字母則不匹配。


、查找以組爲單位的重複字符。組的次數匹配,  \(\)  \{m,\} 

[root@star-linux ~]# grep "\(way\)\{2,\}" text.tx
Say it for alway waywayway ways
[root@star-linux ~]# 

這個意思就是,way這個總體,重複兩次到無限屢次。


、再看看行尾是怎麼回事,查找行尾是 . 的,有意思吧,注意 . 但是元字符,意思就不用說了吧, 那怎麼讓它變成普通字符, 轉義字符\   $

[root@star-linux ~]# grep "\.$" text.tx
it's fine day today.
There are many birds flying in the sky.
[root@star-linux ~]# 


\ 的功能就是轉義。把有意義的字符,轉成普通的。把普通字符轉成有意義的,固然若是是不折不扣的普通字符,再轉也沒用。 


而在正則表達式裏的加\的元字符, 是由於規範的問題所致使的,在grep所用的正則表達式裏,那些須要加\的元字符,都是普通字符,須要加上\來轉義,若是不加的話,它就是普通字符。


而在egrep 所用的擴展的正則表達式中, 除了\< \>和後向引用還要用轉義外, 其它的都不用轉義了,

這又是另外的一種規範, 若是非要加轉義符, 反而又變成普通字符了。


二、擴展正則表達式

主要區別就是次數匹配的元字符不用加\了.

egrep:    
支持擴展的正則表達式實現相似於grep文本過濾功能;grep -E
egrep [OPTIONS] PATTERN [FILE...]
        選項:
                -i, -o, -v, -q, -A, -B, -C
                -G:支持基本正則表達式

元字符

. 任意單個字符
[] 範圍內的任意單個字符
[^] 範圍外的任意單個字符

                     
次數匹配

* 匹配任意次前面的字符
? 匹配0或1次前面的字符
+ 匹配至少1次前面的字符
{m} 匹配其前面的字符m次
{m,n} 匹配其前面的字符m-n次
{m,} 匹配其前面的字符至少m次
{0,n} 至多n次


位置錨定:

^ 行首
$ 行尾
\<或\b 詞首
\>或\b 詞尾


分組:

( ) 分組。  組的功能 一、把多個字符組合成總體來作次數匹配。二、能夠後向引用
| 或者   a|b:a或者b;C|cat:C或cat
(|) 組中的或      (c|C)at:cat或Cat



跟基本正則表達式,除了不用加\之外,沒有什麼其它的區別。這裏來些例子作些參考

取路徑基名:

wKiom1aErEHyytCUAABFnOJGC1w667.jpg

匹配IP地址:

匹配1.0.0.1--223.255.255.254  IP地址的寫法

[root@localhost ~]# ifconfig | egrep '(\<(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\>\.){3}\<(1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\>'
        inet 172.16.249.185  netmask 255.255.0.0  broadcast 172.16.255.255
        inet 192.168.189.190  netmask 255.255.255.0  broadcast 192.168.189.255
        inet 127.0.0.1  netmask 255.0.0.0

wKiom1aErKmDT_E8AABYDYSUDYs319.jpg

匹配IP地址通常也不必必定要匹配1-254之間。也能夠直接匹配0-999的數字。

[root@localhost ~]#  ifconfig | grep -E --color=auto "\<([0-9]{1,3}\.){3}[0-9]{1,3}\>"
        inet 172.16.249.185  netmask 255.255.0.0  broadcast 172.16.255.255
        inet 192.168.189.190  netmask 255.255.255.0  broadcast 192.168.189.255
        inet 127.0.0.1  netmask 255.0.0.0

wKiom1aErangpeVHAABGxTkWMxo769.jpg



2、sed。

sed [OPTION]...  'script'  [input-file] ...
script:地址定界編輯命令

經常使用選項:
    -n:不輸出模式空間中的內容至屏幕;真實的效果就是不顯示沒有區配到的。若是編輯命令是p,那正好只顯示區配到的,若是是d,那就會什麼也不顯示了,由於區配到的給刪除了。
    -e script, --expression=script:多點編輯;
    -f  /PATH/TO/SED_SCRIPT_FILE  從文件讀取命令,每行一個編輯命令;
    -r, --regexp-extended:擴展的正則表達式
    -i[SUFFIX], --in-place[=SUFFIX]:直接編輯原文件 ;

地址定界:
    (1) 空地址:對全文進行處理;
    (2) 單地址:
        #:指定行;
        /pattern/:被此模式所匹配到的每一行;
    (3) 地址範圍
        #,#:
        #,+#:
        #,/pat1/
        /pat1/,/pat2/
        $:最後一行;
    (4) 步進:~
        1~2:全部奇數行
        2~2:全部偶數行

        從第幾行開始,步長爲幾。如0~10,5~3。

        
編輯命令:
    d:刪除;
    p:顯示模式空間中的內容;
    a  \text:在行後面追加文本「text」,支持使用\n實現多行追加;
    i  \text:在行前面插入文本「text」,支持使用\n實現多行插入;

        以上若是text以前沒有要顯示的空字符,能夠不用\.

    c  \text:把匹配到的行替換爲此處指定的文本「text」;
    w /PATH/TO/SOMEFILE:保存模式空間匹配到的行至指定的文件中;
    r  /PATH/FROM/SOMEFILE:讀取指定文件的內容至當前文件被模式匹配到的行後面;文件合併;
    =:爲模式匹配到的行打印行號;
    !:條件取反;格式:!編輯命令;
    s///:查找替換,其分隔符可自行指定,經常使用的有s@@@, s###等;

        替換標記:
            g:全局替換;
            w /PATH/TO/SOMEFILE:將替換成功的結果保存至指定文件中;
            p:顯示替換成功的行;

sed的工做方式

每次在磁盤上讀取一個塊,要看讀取文件的範圍了。而後在內核所緩存的文件數據中按換行符一次讀取一行數據,放到sed本身的內存空間(模式空間)來等待處理。

wKioL1aEul7ATVfMAABoGeY2AxE902.jpg

但處理的時候卻還有點不同,會複製一份數據直接stdout(默認屏幕),一份處處理空間處理。

雖然畫的stdou與處理空間一點關係也沒有,但仍是有點關聯的。在用d編譯命令的時候,不會直接stdout。


地址定界:

例:輸出passwd文件中的2-5行.

[root@localhost ~]# sed -n '2,5p' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@localhost ~]#

通常狀況下,每行數據都會直接stdout出來。-n就是不要stdout。因此上面顯示的只有處理完成的數據。

上面的-n就是經常使用選項,而2,5的部分就是地址定界,p就是編輯命令。

地址定界也能夠用 /pattern/方式,如:

例:輸出root所在的數據。

[root@localhost ~]# sed -n '/root/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost ~]# sed -n '/^root\>/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]#

上面第一個例子由於/pattern/寫的不夠嚴謹,因此匹配到了兩行。


例:顯示sshd用戶到最後一行。

[root@localhost ~]# sed -n '/^sshd\>/,$p' /etc/passwd
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
mageedu:x:1000:1000:MageEdu:/home/mageedu:/bin/bash
sst:x:1001:1001::/home/sst:/bin/bash
[root@localhost ~]#

顯示root和如下3行。

[root@localhost ~]# sed -n '/^root\>/,+3p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
[root@localhost ~]#


步進,從第幾行開始,每次跨幾行。如:

從20行開始,以3爲跨度。

[root@localhost ~]# sed -n '20~3p' /etc/passwd
rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
chrony:x:996:994::/var/lib/chrony:/sbin/nologin
ntp:x:38:38::/etc/ntp:/sbin/nologin

編輯命令中有個=號,是用來顯示所匹配到的數據的行號。

[root@localhost ~]# sed -n '20~3=' /etc/passwd
20
23
26


編輯命令

上面的p和=號都有了,下面再來幾個。(a,i,c)

[root@localhost ~]# sed '/^root\>/a drink tea' /etc/passwd
root:x:0:0:root:/root:/bin/bash
drink tea
bin:x:1:1:bin:/bin:/sbin/nologin

在root所在行的下面附加一行。a就是這個功能。

添加多行。單引號是絕對引用因此回車也能夠被sed識別,用\n表明換行也能夠。若是不定界,就是空地址,會在全部行的下面加上這一堆數據。

[root@localhost ~]# sed '2a drink tea\
> drink coffee\
> drink apple juicd' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
drink tea
drink coffee
drink apple juicd


而i就是在root行的下面插入一行。

[root@localhost ~]# sed '/^root\>/i drink tea' /etc/passwd
drink tea
root:x:0:0:root:/root:/bin/bash

而c就是直接修改root行。

[root@localhost ~]# sed '/^root\>/c drink tea' /etc/passwd
drink tea
bin:x:1:1:bin:/bin:/sbin/nologin


編輯命令:d

sed '2d'           刪除第二行

sed '2,5d'         刪除2到5行
sed '2,$d'         刪除2到尾行
sed '/star/d'      刪除有star的行    


編輯命令:s

sed '行號s/老的字符串/新的字符串/g'         

以行單位查找匹配的字符串,而後替換。
                                                        
sed 's/:/?/g'                  把數據中全部行的:變成?。
sed '2,5s/:/?/g'               把2-5行的:變成?。
sed '/star/s/#/#star/g'     把有star的行中的#變成#star。


刪除/etc/fstab文件中全部以#開頭的行的行首的#號及#後面的全部空白字符;而且刪除空行。

[root@localhost ~]# sed -e 's/^#[[:space:]]*//g' -e '/^$/d' /etc/fstab
/etc/fstab
Created by anaconda on Sun Dec  6 11:02:42 2015
Accessible filesystems, by reference, are maintained under '/dev/disk'
See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
UUID=1f89bbf3-c25c-4b4b-aac8-284c19077770 /                       xfs     defaults        0 0
UUID=1591ce0b-5726-4e03-8cbe-0a2105169930 /boot                   xfs     defaults        0 0
UUID=0a527ef7-eb80-4155-9cd5-ea12fba99515 /usr                    xfs     defaults        0 0
UUID=7f892a1b-055a-498f-a812-64086132157a swap                    swap    defaults        0 0
[root@localhost ~]#


輸出一個絕對路徑給sed命令,取出其目錄,其行爲相似於dirname;

[root@localhost ~]# echo "/etc/sysconfig/network-scripts/ifcfg-eno16777736/" | sed -r 's/[^\/]+\/?$//'
/etc/sysconfig/network-scripts/
[root@localhost ~]#


把/etc/fstab文件中的全部UUID的行,最後面的0變成1.

[root@localhost ~]# sed -r '/^UUID\>/s/0([[:space:]]*)$/1\1/g' /etc/fstab

#
# /etc/fstab
# Created by anaconda on Sun Dec  6 11:02:42 2015
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=1f89bbf3-c25c-4b4b-aac8-284c19077770 /                       xfs     defaults        0 1
UUID=1591ce0b-5726-4e03-8cbe-0a2105169930 /boot                   xfs     defaults        0 1
UUID=0a527ef7-eb80-4155-9cd5-ea12fba99515 /usr                    xfs     defaults        0 1
UUID=7f892a1b-055a-498f-a812-64086132157a swap                    swap    defaults        0 1


取出/boot/grub/grub.conf文件中的內核文件名稱。

[root@localhost ~]# sed -n 's/^[[:space:]]\+kernel \/\(vmlinuz[^[:space:]]\+\).*$/\1/p' /boot/grub/grub.conf
vmlinuz-2.6.32-573.el6.x86_64
[root@localhost ~]#



謝謝瀏覽,有什麼不對的地方,還請指出。謝謝。

相關文章
相關標籤/搜索