1. 簡介
grep: Gloabal Search Regular Expression and Print out the line,意為全局搜索正則表達式并打印文本行。所以
- grep是一個強大的文本搜索工具
- grep與正則表達式聯系緊密
之后也會從這兩個大的方面來詳細介紹。grep命令的基本語法如下:
grep [options] pattern [file...]
[options]表示選項,具體的命令選項見下表。pattern表示要匹配的模式(包括目標字符串、變量或者正則表達式),file表示要查詢的文件名,可以是一個或者多個。pattern后面所有的字符串參數都會被理解為文件名。
選項 | 說明 |
---|---|
-c ????? | 只打印匹配的文本行的行數,不顯示匹配的內容 |
-i | 匹配時忽略字母的大小寫 |
-h | 當搜索多個文件時,不顯示匹配文件名前綴 |
-n | 列出所有的匹配的文本行,并顯示行號 |
-l | 只列出含有匹配的文本行的文件的文件名,而不顯示具體的匹配內容 |
-s | 不顯示關于不存在或者無法讀取文件的錯誤信息 |
-v | 只顯示不匹配的文本行 |
-w | 匹配整個單詞 |
-x | 匹配整個文本行 |
-r | 遞歸搜索,搜索當前目錄和子目錄 |
-q | 禁止輸出任何匹配結果,而是以退出碼的形式表示搜索是否成功,其中0表示找到了匹配的文本行 |
-b | 打印匹配的文本行到文件頭的偏移量,以字節為單位 |
-E | 支持擴展正則表達式 |
-P | 支持Perl正則表達式 |
-F | 不支持正則表達式,將模式按照字面意思匹配 |
二、grep簡單應用場景
首先介紹一下我的實驗環境,在/home/tyrone下建立3個簡單的txt文件:
#----------------------/home/tyrone/text1.txt---------------------
hello world
mailx
uuen
letitia
#----------------------/home/tyrone/text2.txt---------------------
hello world,this is for grep test
#----------------------/home/tyrone/text3.txt---------------------
hello world
tyrone
(1)多文件查詢,file之間用空格隔開
grep -i "hello world" test1.txt test2.txt
#輸出結果
test1.txt:hello world
test2.txt:hello world,this is for grep test
(2)多模式匹配,模式之間為“邏輯或”的關系,匹配任意一個
#方法1:使用-e選項
grep -e "hello world" -e "mailx" -r /home/tyrone
#方法2:使用正則表達式,-E
grep -E "hello world|mailx" -r /home/tyrone
#方法3:使用正則表達式,egrep,同grep -E等效
egrep "hello world|mailx" -r /home/tyrone
#輸出結果均相同:
/home/tyrone/test1.txt:hello world
/home/tyrone/test1.txt:mailx
/home/tyrone/test2.txt:hello world,this is for grep test
/home/tyrone/test3.txt:hello world
(3)多模式匹配,模式之間為“邏輯與”的關系,匹配所有模式。
這個問題我查閱了很多方法,并逐一試驗了一下。基本思想大致相同:先匹配一個模式,然后grep下面一個模式,將前一次grep的結果作為要查詢文件路徑依次向后傳遞。
注意:前一次grep的結果必須加上-l選項,否則會把匹配成功的文件內容作為要查詢的文件名向后傳遞。
我希望做到的是能夠顯示出同時包含模式的文件,并且跟隨顯示匹配每個模式的內容。可惜我現在找到的方法都僅僅能夠顯示匹配最后一個模式的內容。
#方法1:比較笨,將其按一次的結果重定向到一個文件,然后xargs grep來依次讀取。
grep -i "hello world" -rl /home/tyrone >> reslut.txt
cat result.txt | xargs grep -i "mailx"
#輸出結果
/home/tyrone/test1.txt:mailx
#方法2:直接利用管道
grep -i "hello world" -rl /home/tyrone | xargs grep -i "mailx"
#輸出結果
/home/tyrone/test1.txt:mailx
#方法3:使用find,適合于需要靈活判斷條件的場景。例如查找指定路徑下,同時匹配多個模式的txt文件。
#注意:本例中“mailx”后面的命令必須加上反引號 ` ,否則會被當作要查詢的文件名。
grep -i "mailx" `find /home/tyrone -type f -name "*.txt" -exec grep -l "hello world" {} \;`
#輸出結果
/home/tyrone/test1.txt:mailx
#方法4:同3
find /home/tyrone -name "*.txt" -exec grep -l "hello world" {} \; | xargs grep -i "mailx"
#輸出結果
/home/tyrone/test1.txt:mailx
最后不得不感慨一下linux命令的組合方式,能像積木一樣堆積出無窮的組合,是時候展現真正的想象力了。。。
(4)查找指定用戶的進程
ps是查看當前進程的指令,e表示所有進程,f表示全格式。
ps -ef | grep "tyrone"
#輸出結果
root 27200 1827 0 Jun15 ? 00:00:00 sshd: tyrone [priv]
tyrone 27434 27433 0 Jun15 pts/50 00:00:00 -bash
tyrone 43316 27434 2 02:14 pts/50 00:00:00 ps -ef
tyrone 43317 27434 0 02:14 pts/50 00:00:00 grep tyrone
三、團結就是力量
現在要搞一個腳本把前面總結的命令一鍋燉了。先搜索同時匹配多個模式的文件,把它們先備份之后,替換目標字符串:
#----------------------/home/tyrone/myshell.ksh---------------------
#! /bin/ksh
grep "hello world" -rl /home/tyrone | xargs grep -l "mailx" > /home/tyrone/result5.txt
cat result5.txt | while read line
do
cp ${line} ${line}.bak20150616
sed -i "s/hello world/letitia/g" `grep "hello world" -rl ${line}`
done
#輸出結果:只有test1.txt滿足條件,將"hello world"替換成了"letitia"
#哦對了。。還有我的shell文件也同時包含了這兩個模式,可以通過find限定文件后綴,不表
#----------------------/home/tyrone/text1.txt---------------------
letitia
mailx
uuen
letitia
#----------------------/home/tyrone/text2.txt---------------------
hello world,this is for grep test
#----------------------/home/tyrone/text3.txt---------------------
hello world
tyrone
#----------------/home/tyrone/text1.txt.bak20150616---------------
hello world
mailx
uuen
letitia
四、下回分解
grep與正則表達式的故事