關于取路徑名與基名的探討和擴展
這兩天學習grep , egrep , sed ,有一個問題一直在糾結,就是關于取基名和路徑名的問題,雖然對于有的伙伴來說很簡單,但有時候有的問題就是有點想不通,研究學習了兩天,終于有點眉目,寫寫心得免得以后忘記了。
由于一個練習題引發的糾結:(我一直沒有搞懂如何通過識別分隔符或特使字段使得可以把任何基名曲出來,只知道一大堆符號就完成了,奇怪啊,奇怪啊……一天沒吃飯的,智商問題?年紀大了?)
練習題一 :取出/etc/rc.d/init.d/functions中其基名?取出上面路徑的目錄名?分別使用grep , egrep ,sed 給出解決辦法?
其實小伙伴都知道其基名就是 functions,路徑名為/etc/rc.d/init.d/,:
§ grep解決辦法
·grep取基名:(通過公式)
[root@wCentos7 Packages]# echo "/etc/rc.d/init.d/functions" | grep -o ‘[^/]\+/\?$' functions
※詳解:
分析語句:我們需要的functions,我們可以想到在行尾一定會用$,匹配是從前面想后面匹配,到匹配到functions 前面的 / 時,我們就讓為我們已經可以得到我們需要的基名了,但是我們不確定 functions到底有多少字符, 所以我們就可以使用 [^/]\+ 表示,后面的 /\? 表示最后面的 /可有可無 ,結束為 $.
'[^/]\+/\?$' : 起始位非 / 開始([^/]限定functions前面),并且后面可以由很多個非 / 的字符(\+/通用顯示functions的字符數量),尾部有沒有 /都無所謂(/\?$) ,限定尾部即可($)。
·grep取路徑名名:(貌似取路徑名沒有通用的公式)
[root@wCentos7 Packages]#echo "/etc/rc.d/init.d/functions/system" | grep -o '^.*/' /etc/rc.d/init.d/
§ egrep解決辦法:
·egrep取基名:(通過公式)
[root@wCentos7 Packages]#echo '/etc/rc.d/init.d/functions' | egrep -o '[^/]+/?$' functions
·egrep取路徑名名:(貌似取路徑名沒有通用的公式)
[root@wCentos7 Packages]#echo "/etc/rc.d/init.d/functions/system" | grep -o '^.*/' /etc/rc.d/init.d/
§ sed解決辦法:
(sed的功能比較強大,有一點得注意,sed是一行一行數據的處理,當某個模式被匹配了,有刪除的動作時刪除整個行,不是匹配的模式;所以我們只能想辦法替換調匹配的模式達到我們取出基明或路徑名。)
·sed取基名:(通過公式)
[root@wCentos7 Packages]# echo '/etc/rc.d/init.d/functions' | sed 's@[^/]\+/\?$@12356 @' #替換內容 /etc/rc.d/init.d/12356
#我們上面其實找出來我們需要的字段了functions被替換成為 123456,我們想辦法讓我們得到的結果成為我們的模式即可,
在正則表達式中我們學習了分組和引用,所以我們就可以使用以下的命令即可:
[root@wCentos7 Packages]# echo '/etc/rc.d/init.d/functions' | sed 's@.*/\([^/]\+/\?$\)@\1@' functions
※詳解:s@.*/\([^/]\+/\?$\)@\1@ :這個語句已經是匹配了整個語句,可以通過grep來查詢實驗
[root@wCentos7 Packages]# echo "/etc/rc.d/init.d/functions" | grep '.*/\([^/]\+/\?$\)' /etc/rc.d/init.d/functions
#.*/\([^/]\+/\?$\) 通過grep查詢時匹配整個語句的;
[root@wCentos7 Packages]# echo "/etc/rc.d/init.d/functions" | grep -o '[^/]\+/\?$' functions
#分組里面的[^/]\+/\?$ 通過測試時匹配基名的。
所以我們把分組內的數據 覆蓋整個行即可顯示我們需要的基名:
s@.*/\([^/]\+/\?$\)@\1@ : 把分組1的數據替換調前面的數據;
分組1的數據為: ([^/]\+/\?$\) 就是 基名 functions
路徑名: .*/\ /etc/rc.d/init.d/
合成就是:functions替換掉 /etc/rc.d/init.d/functions
·sed取路徑名名:(通過公式)
[root@wCentos7 Packages]# echo '/etc/rc.d/init.d/functions/' | sed 's@\([^/]\+/\?$\)@@' /etc/rc.d/init.d/
#這個應該好理解的,就是把基名替換為空白就得到我們的路徑名了,一定記得不是刪除的。
§ ·擴展:理解以上的概念我們來做下面的題目,并寫出通用的公式吧!
練習題:統計centos安裝光盤中Package目錄下的所有rpm文件的以.分隔倒數第二個字段的重復次數?
我們通過關盤可以看到Package的文件名大概都為:
[root@wCentos7 Packages]# ls #不一一列舉 名稱.版本.架構;平臺.名稱,我們就需要獲得平臺的數據統計 yum-plugin-protectbase-1.1.31-34.el7.noarch.rpm yum-plugin-remove-with-leaves-1.1.31-34.el7.noarch.rpm yum-utils-1.1.31-34.el7.noarch.rpm zenity-3.8.0-5.el7.x86_64.rpm zip-3.0-10.el7.x86_64.rpm zlib-1.2.7-15.el7.i686.rpm zlib-1.2.7-15.el7.x86_64.rpm zziplib-utils-0.13.62-5.el7.x86_64.rpm
我們借鑒上面的思路,我們需要取出 noarch x86_64 i686的字樣,其實我們可以發現,我們取出兩個小數點的數據統計就可以的,和去基名是不是一樣的啊,思路有了我們就可以直接想辦法取出倒數兩個小數點的數據統計排序就行的。
我得到的命令如下:
[root@wCentos7 Packages]# ls | sed 's@.*\.\([^.]\+\.rpm$\)@\1@' | sort | uniq -c 2000 i686.rpm 2938 noarch.rpm 1 TRANS.TBL 4069 x86_64.rpm
※詳解: sed 's@.*\.\([^.]\+\.rpm$\)@\1@'
s@ @ @ : 替換命令;分組1數據替換文件名稱的完整名稱
([^.]\+\.rpm$\) : 匹配 倒數2個小數點的數據 如:x86_64.rpm noarch.rpm i686.rpm;
.*\.\([^.]\+\.rpm$\) :匹配文件名稱的完整名稱 如:zziplib-utils-0.13.62-5.el7.x86_64.rpm;
\1 :即為x86_64.rpm noarch.rpm i686.rpm的數據。
※通用公式:
[root@wCentos7 Packages]# ls | sed 's@.*\.\([^.]\+\.[^.]\+$\)@\1@' | sort | uniq -c 2000 i686.rpm 2938 noarch.rpm 1 TRANS.TBL 4069 x86_64.rpm
#把 .rpm 這一節換成 \.[^.]\+ 即可得到上面的表達式
[root@wCentos7 Packages]# ls | sed 's@.*\(\.[^.]\+\.[^.]\+$\)@\1@' | sort | uniq -c 2000 .i686.rpm 2938 .noarch.rpm 1 TRANS.TBL 4069 .x86_64.rpm #把括號外面的 \. 移動括號
[root@wCentos7 Packages]# ls | sed 's@.*\(\(\.[^.]\+\)\{2\}$\)@\1@' | sort | uniq -c 2000 .i686.rpm 2938 .noarch.rpm 1 TRANS.TBL 4069 .x86_64.rpm
#把兩個 \.[^.]\+ 換成 \(\.[^.]\+\)\{2\} 即可得到上面的表達式
總結:
grep , egrep , sed 等等命令實現復雜的功能都需要配合 正則表達式和擴展正則表達式,深入的理解正則表達式和擴展正則表達式對以后我們對工具的理解和使用有很好的幫助,個人感覺還可以提供我們對于程序的腳本編程有一定的理解。
個人一直認為,理解其工作原理對于使用工具有很好的幫助,不能一味的按照教程上上敲,記住順序還是會很快遺忘的,不過理解了其簡單原理,還是需要多多的敲命令的,不讓命令參數都忘記了如何是好。(筆者也是很多命令參數記不住啊,希望老師多出些練習題,實際實用的練習題的,呵呵)
原創文章,作者:linux_root,如若轉載,請注明出處:http://www.www58058.com/30328