在基因解碼過(guò)程,常常需要對(duì)儲(chǔ)存在文本文件中的基因信息進(jìn)行處理,本文介紹基因檢測(cè)的科學(xué)依據(jù)的處理過(guò)程的一些常用Linux文本操作命令,包括wc(統(tǒng)計(jì))、cut(切分)、sort(排序)、uniq(去重)、grep(查找)、sed(替換、插入、刪除)、awk(文本分析)。
1.統(tǒng)計(jì)命令——wc
統(tǒng)計(jì)文件里面有多少單詞,多少行,多少字符。
1.1 wc語(yǔ)法
# wc [-lwm] 選項(xiàng)與參數(shù): -l :僅列出行; -w :僅列出多少字(英文單字); -m :多少字符;
1.2 wc使用
#wc /jiyinjiance/jiaxue.txt #這里 /jiyinjiance/jiaxue.txt是文件名 40 45 1719 /jiyinjiance/jiaxue.txt
40是行數(shù),45是單詞數(shù),1719是字節(jié)數(shù)
wc的命令比較簡(jiǎn)單使用,每個(gè)參數(shù)使用如下:
#wc -l /jiyinjiance/jiaxue.txt #統(tǒng)計(jì)行數(shù),在對(duì)記錄數(shù)時(shí),很常用 40 /jiyinjiance/jiaxue.txt #表示系統(tǒng)有40個(gè)賬戶 #wc -w /jiyinjiance/jiaxue.txt #統(tǒng)計(jì)單詞出現(xiàn)次數(shù) 45 /jiyinjiance/jiaxue.txt #wc -m /jiyinjiance/jiaxue.txt #統(tǒng)計(jì)文件的字節(jié)數(shù)
1719 /jiyinjiance/jiaxue.txt2.切分命令——cut
2.1 cut語(yǔ)法
cut [-bn] [file] 或 cut [-c] [file] 或 cut [-df] [file]
使用說(shuō)明
cut 命令從文件的每一行剪切字節(jié)、字符和字段并將這些字節(jié)、字符和字段寫至標(biāo)準(zhǔn)輸出。
如果不指定 File 參數(shù),cut 命令將讀取標(biāo)準(zhǔn)輸入。必須指定 -b、-c 或 -f 標(biāo)志之一。
主要參數(shù)
-b :以字節(jié)為單位進(jìn)行分割。這些字節(jié)位置將忽略多字節(jié)字符邊界,除非也指定了 -n 標(biāo)志。
-c :以字符為單位進(jìn)行分割。
-d :自定義分隔符,默認(rèn)為制表符。
-f :與-d一起使用,指定顯示哪個(gè)區(qū)域。
-n :取消分割多字節(jié)字符。僅和 -b 標(biāo)志一起使用。如果字符的賊后一個(gè)字節(jié)落在由 -b 標(biāo)志的 List 參數(shù)指示的<br />范圍之內(nèi),該字符將被寫出;否則,該字符將被排除。
2.2 cut一般以什么為依據(jù)呢? 也就是說(shuō),我怎么告訴cut我想定位到的剪切內(nèi)容呢?
cut命令主要是接受三個(gè)定位方法:
先進(jìn),字節(jié)(bytes),用選項(xiàng)-b
第二,字符(characters),用選項(xiàng)-c
第三,域(fields),用選項(xiàng)-f
2.3 以“字節(jié)”為單位切分
舉個(gè)例子吧,當(dāng)你執(zhí)行ps命令時(shí),會(huì)輸出類似如下的內(nèi)容:
$ who rocrocket :0 2009-01-08 11:07 rocrocket pts/0 2009-01-08 11:23 (:0.0) rocrocket pts/1 2009-01-08 14:15 (:0.0)
如果我們想提取每一行的第3個(gè)字節(jié),就這樣:
$ who|cut -b 3
如果“字節(jié)”定位中,我想提取第3,第4、第5和第8個(gè)字節(jié),怎么辦?
-b支持形如3-5的寫法,而且多個(gè)定位之間用逗號(hào)隔開(kāi)就成了。看看例子吧:
$ who|cut -b 3-5,8 croe croe croe
但有一點(diǎn)要注意,cut命令如果使用了-b選項(xiàng),那么執(zhí)行此命令時(shí),cut會(huì)先把-b后面所有的定位進(jìn)行從小到大排序,然后再提取。因此這跟我們書(shū)寫的順序沒(méi)有關(guān)系。這個(gè)例子就可以說(shuō)明這個(gè)問(wèn)題:
$ who|cut -b 8,3-5 croe croe croe
還有哪些類似“3-5”這樣的小技巧,列舉一下吧!
$ who rocrocket :0 2009-01-08 11:07 rocrocket pts/0 2009-01-08 11:23 (:0.0) rocrocket pts/1 2009-01-08 14:15 (:0.0) $ who|cut -b -3 roc roc roc $ who|cut -b 3- crocket :0 2009-01-08 11:07 crocket pts/0 2009-01-08 11:23 (:0.0) crocket pts/1 2009-01-08 14:15 (:0.0)
想必你也看到了,-3表示從先進(jìn)個(gè)字節(jié)到第三個(gè)字節(jié),而3-表示從第三個(gè)字節(jié)到行尾。如果你細(xì)心,你可以看到這兩種情況下,都包括了第三個(gè)字節(jié)“c”。如果我執(zhí)行who|cut -b -3,3-,你覺(jué)得會(huì)如何呢?答案是輸出整行,不會(huì)出現(xiàn)連續(xù)兩個(gè)重疊的c的。
$ who|cut -b -3,3- rocrocket :0 2009-01-08 11:07 rocrocket pts/0 2009-01-08 11:23 (:0.0) rocrocket pts/1 2009-01-08 14:15 (:0.0)
2.4 以"字符"為單位切分
下面例子你似曾相識(shí),提取第3,第4,第5和第8個(gè)字符:
$ who|cut -c 3-5,8 croe croe croe
不過(guò),看著怎么和-b沒(méi)有什么區(qū)別???莫非-b和-c作用一樣? 其實(shí)不然,看似相同,只是因?yàn)檫@個(gè)例子舉的不好,who輸出的都是單字節(jié)字符,所以用-b和-c沒(méi)有區(qū)別,如果你提取中文,區(qū)別就看出來(lái)了,來(lái),看看中文提取的情況:
$ cat cut_ch.txt 星期一 星期二 星期三 星期四 $ cut -b 3 cut_ch.txt ? ? ? ? $ cut -c 3 cut_ch.txt 一 二 三 四
看到了吧,用-c則會(huì)以字符為單位,輸出正常;而-b只會(huì)傻傻的以字節(jié)(8位二進(jìn)制位)來(lái)計(jì)算,輸出就是亂碼。既然提到了這個(gè)知識(shí)點(diǎn),就再補(bǔ)充一句,如果你學(xué)有余力,就提高一下。當(dāng)遇到多字節(jié)字符時(shí),可以使用-n選項(xiàng),-n用于告訴cut不要將多字節(jié)字符拆開(kāi)。
$ cat cut_ch.txt |cut -b 2 ? ? ? ? $ cat cut_ch.txt |cut -nb 2 等價(jià)于 $ cat cut_ch.txt |cut -nb 1,2,3 星 星 星 星
2.5 以"域"為單位切分
為什么會(huì)有“域”的提取呢,因?yàn)閯偛盘岬降?b和-c只能在固定格式的文檔中提取信息,而對(duì)于非固定格式的信息則束手無(wú)策。這時(shí)候“域”就派上用場(chǎng)了。如果你觀察過(guò)/jiyinjiance/jiaxue.txt文件,你會(huì)發(fā)現(xiàn),它并不像who的輸出信息那樣具有固定格式,而是比較零散的排放。但是,冒號(hào)在這個(gè)文件的每一行中都起到了非常重要的作用,冒號(hào)用來(lái)隔開(kāi)每一個(gè)項(xiàng)。
我們很幸運(yùn),cut命令提供了這樣的提取方式,具體的說(shuō)就是設(shè)置“間隔符”,再設(shè)置“提取第幾個(gè)域”,就OK了!
以/jiyinjiance/jiaxue.txt的前五行內(nèi)容為例:
$ cat /jiyinjiance/jiaxue.txt|head -n 5 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 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin $ cat /jiyinjiance/jiaxue.txt|head -n 5|cut -d : -f 1 root bin daemon adm lp
看到了吧,用-d來(lái)設(shè)置間隔符為冒號(hào),然后用-f來(lái)設(shè)置我要取的是先進(jìn)個(gè)域,再按回車,所有的用戶名就都列出來(lái)了!呵呵 有成就感吧!
當(dāng)然,在設(shè)定-f時(shí),也可以使用例如3-5或者4-類似的格式:
$ cat /jiyinjiance/jiaxue.txt|head -n 5|cut -d : -f 1,3-5 root:0:0:root bin:1:1:bin daemon:2:2:daemon adm:3:4:adm lp:4:7:lp $ cat /jiyinjiance/jiaxue.txt|head -n 5|cut -d : -f 1,3-5,7 root:0:0:root:/bin/bash bin:1:1:bin:/sbin/nologin daemon:2:2:daemon:/sbin/nologin adm:3:4:adm:/sbin/nologin lp:4:7:lp:/sbin/nologin $ cat /jiyinjiance/jiaxue.txt|head -n 5|cut -d : -f -2 root:x bin:x daemon:x adm:x lp:x
2.6 cut的弊端:
如果遇到空格和制表符時(shí),怎么分辨呢?我覺(jué)得有點(diǎn)亂,怎么辦?
有時(shí)候制表符確實(shí)很難辨認(rèn),有一個(gè)方法可以看出一段空格到底是由若干個(gè)空格組成的還是由一個(gè)制表符組成的。
$ cat tab_space.txt this is tab finish. this is several space finish. $ sed -n l tab_space.txt this is tab finish.$ this is several space finish.$
看到了吧,如果是制表符(TAB),那么會(huì)顯示為 符號(hào),如果是空格,就會(huì)原樣顯示。通過(guò)此方法即可以判斷制表符和空格了。注意,上面sed -n后面的字符是L的小寫字母哦,不要看錯(cuò)。
我應(yīng)該在cut -d中用什么符號(hào)來(lái)設(shè)定制表符或空格呢?
其實(shí)cut的-d選項(xiàng)的默認(rèn)間隔符就是制表符,所以當(dāng)你就是要使用制表符的時(shí)候,有效就可以省略-d選項(xiàng),而直接用-f來(lái)取域就可以了。如果你設(shè)定一個(gè)空格為間隔符,那么就這樣:
$cat tab_space.txt |cut -d ' ' -f 1 this this
注意,兩個(gè)單引號(hào)之間可確實(shí)要有一個(gè)空格哦,不能偷懶。而且,你只能在-d后面設(shè)置一個(gè)空格,可不許設(shè)置多個(gè)空格,因?yàn)閏ut只允許間隔符是一個(gè)字符。
$ cat tab_space.txt |cut -d ' ' -f 1 cut: the delimiter must be a single character Try `cut --help' for more information.
此外,cut在處理多空格的時(shí)候會(huì)更麻煩,因?yàn)?span style="color: rgba(255, 0, 0, 1); background-color: rgba(255, 255, 0, 1)">cut只擅長(zhǎng)處理“以一個(gè)字符間隔”的文本內(nèi)容。
3.排序命令——sort
3.1 sort語(yǔ)法:
sort命令是幫我們依據(jù)不同的數(shù)據(jù)類型進(jìn)行排序,其語(yǔ)法及常用參數(shù)格式:
sort [-bcfMnrtk][源文件][-o 輸出文件]
補(bǔ)充說(shuō)明:sort可針對(duì)文本文件的內(nèi)容,以行為單位來(lái)排序。
參數(shù):
-b 忽略每行前面開(kāi)始出的空格字符。
-c 檢查文件是否已經(jīng)按照順序排序。
-f 排序時(shí),忽略大小寫字母。
-M 將前面3個(gè)字母依照月份的縮寫進(jìn)行排序。
-n 依照數(shù)值的大小排序。
-o<輸出文件> 將排序后的結(jié)果存入指定的文件。
-r 以相反的順序來(lái)排序。
-t<分隔字符> 指定排序時(shí)所用的欄位分隔字符。
-k 選擇以哪個(gè)區(qū)間進(jìn)行排序。
3.2 sort的使用
下面通過(guò)幾個(gè)例子來(lái)講述Sort的使用。
?。?)sort將文件的每一行作為一個(gè)單位,相互比較,比較原則是從首字符向后,依次按ASCII碼值進(jìn)行比較,賊后將他們按升序輸出。
$ cat seq.txt banana apple pear orange $ sort seq.txt apple banana orange pear
用戶可以保存排序后的文件內(nèi)容,或把排序后的文件內(nèi)容輸出至打印機(jī)。下例中用戶把排序后的文件內(nèi)容保存到名為result的文件中。
$ Sort seq.txt > result
?。?)sort的-u選項(xiàng)
它的作用很簡(jiǎn)單,就是在輸出行中去除重復(fù)行。
$ cat seq.txt banana apple pear orange pear $ sort seq.txt apple banana orange pear pear $ sort -u seq.txt apple banana orange pear
pear由于重復(fù)被-u選項(xiàng)無(wú)情的刪除了。
?。?)sort的-r選項(xiàng)
sort默認(rèn)的排序方式是升序,如果想改成降序,就加個(gè)-r就搞定了。
$ cat number.txt 1 3 5 2 4 $ sort number.txt 1 2 3 4 5 $ sort -r number.txt 5 4 3 2 1
(4)sort的-o選項(xiàng)
由于sort默認(rèn)是把結(jié)果輸出到標(biāo)準(zhǔn)輸出,所以需要用重定向才能將結(jié)果寫入文件,形如sort filename > newfile。
但是,如果你想把排序結(jié)果輸出到原文件中,用重定向可就不行了。
$ sort -r number.txt > number.txt $ cat number.txt $
看,竟然將number清空了。就在這個(gè)時(shí)候,-o選項(xiàng)出現(xiàn)了,它成功的解決了這個(gè)問(wèn)題,讓你放心的將結(jié)果寫入原文件。這或許也是-o比重定向的少有優(yōu)勢(shì)所在。
$ cat number.txt 1 3 5 2 4 $ sort -r number.txt -o number.txt $ cat number.txt 5 4 3 2 1
(5) sort的-n選項(xiàng)
你有沒(méi)有遇到過(guò)10比2小的情況。我反正遇到過(guò)。出現(xiàn)這種情況是由于排序程序?qū)⑦@些數(shù)字按字符來(lái)排序了,排序程序會(huì)先比較1和2,顯然1小,所以就將10放在2前面嘍。這也是sort的一貫作風(fēng)。我們?nèi)绻敫淖冞@種現(xiàn)狀,就要使用-n選項(xiàng),來(lái)告訴sort,“要以數(shù)值來(lái)排序”!
$ cat number.txt 1 10 19 11 2 5 $ sort number.txt 1 10 11 19 2 5 $ sort -n number.txt 1 2 5 10 11 19
?。?)sort的-t選項(xiàng)和-k選項(xiàng)
如果有一個(gè)文件的內(nèi)容是這樣:
$ cat facebook.txt banana:30:5.5 apple:10:2.5 pear:90:2.3 orange:20:3.4
這個(gè)文件有三列,列與列之間用冒號(hào)隔開(kāi)了,先進(jìn)列表示水果類型,第二列表示水果數(shù)量,第三列表示水果價(jià)格。那么我想以水果數(shù)量來(lái)排序,也就是以第二列來(lái)排序,如何利用sort實(shí)現(xiàn)?幸好,sort提供了-t選項(xiàng),后面可以設(shè)定間隔符。指定了間隔符之后,就可以用-k來(lái)指定列數(shù)了。
$ sort -n -k 2 -t ‘:’ facebook.txt apple:10:2.5 orange:20:3.4 banana:30:5.5 pear:90:2.3
?。?) 其他的sort常用選項(xiàng)
-f 會(huì)將小寫字母都轉(zhuǎn)換為大寫字母來(lái)進(jìn)行比較,亦即忽略大小寫
-c 會(huì)檢查文件是否已排好序,如果亂序,則輸出先進(jìn)個(gè)亂序的行的相關(guān)信息,賊后返回1
-C 會(huì)檢查文件是否已排好序,如果亂序,不輸出內(nèi)容,僅返回1
-M 會(huì)以月份來(lái)排序,比如JAN小于FEB等等
-b 會(huì)忽略每一行前面的所有空白部分,從先進(jìn)個(gè)可見(jiàn)字符開(kāi)始比較。
4.去重命令——uniq
4.1 uniq語(yǔ)法
uniq命令可以去除排序過(guò)的文件中的重復(fù)行,因此uniq經(jīng)常和sort合用。也就是說(shuō),為了使uniq起作用,所有的重復(fù)行必須是相鄰的。
# uniq [-icu] 選項(xiàng)與參數(shù): -i :忽略大小寫字符的不同; -c :進(jìn)行計(jì)數(shù) -u :只顯示少有的行
4.2 uniq的使用
testfile的內(nèi)容如下:
# cat testfile hello world friend hello world hello
直接刪除未經(jīng)排序的文件,將會(huì)發(fā)現(xiàn)沒(méi)有任何行被刪除:
#uniq testfile hello world friend hello world hello
排序文件,默認(rèn)是去重:
#cat words | sort |uniq friend hello world
排序之后刪除了重復(fù)行,同時(shí)在行首位置輸出該行重復(fù)的次數(shù):
#sort testfile | uniq -c 1 friend 3 hello 2 world
僅顯示存在重復(fù)的行,并在行首顯示該行重復(fù)的次數(shù):
#sort testfile | uniq -dc 3 hello 2 world
僅顯示不重復(fù)的行:
#sort testfile | uniq -u friend
5.查找命令——grep
5.1 grep語(yǔ)法
Linux系統(tǒng)中g(shù)rep命令是一種強(qiáng)大的文本搜索工具,它能使用正則表達(dá)式搜索文本,并把匹 配的行打印出來(lái)。grep全稱是Global Regular Expression Print,表示全局正則表達(dá)式版本,它的使用權(quán)限是所有用戶。
grep [options]
主要參數(shù)
[options]主要參數(shù):
?。璫:只輸出匹配行的計(jì)數(shù)。
?。璉:不區(qū)分大 小寫(只適用于單字符)。
?。環(huán):查詢多文件時(shí)不顯示文件名。
?。璴:查詢多文件時(shí)只輸出包含匹配字符的文件名。
?。璶:顯示匹配行及 行號(hào)。
?。璼:不顯示不存在或無(wú)匹配文本的錯(cuò)誤信息。
?。璿:顯示不包含匹配文本的所有行。
pattern正則表達(dá)式主要參數(shù):
?。?忽略正則表達(dá)式中特殊字符的原有含義。
^:匹配正則表達(dá)式的開(kāi)始行。
$: 匹配正則表達(dá)式的結(jié)束行。
<:從匹配正則表達(dá) 式的行開(kāi)始。
>:到匹配正則表達(dá)式的行結(jié)束。
[ ]:?jiǎn)蝹€(gè)字符,如[A]即A符合要求 。
[ - ]:范圍,如[A-Z],即A、B、C一直到Z都符合要求 。
。:所有的單個(gè)字符。
* :有字符,長(zhǎng)度可以為0。
5.2 grep簡(jiǎn)單使用
顯示所有以d開(kāi)頭的文件中包含 test的行:
$ grep 'test' d*
顯示在aa,bb,cc文件中匹配test的行:
$ grep 'test' aa bb cc
輸出匹配行的計(jì)數(shù):
grep -c "48" data.doc #輸出文檔中含有48字符的行數(shù)
顯示匹配行和行數(shù):
grep -n "48" data.doc #顯示所有匹配48的行和行號(hào)
顯示非匹配的行:
grep -vn "48" data.doc #輸出所有不包含48的行
顯示非匹配的行:
grep -vn "48" data.doc #輸出所有不包含48的行
大小寫敏感:
grep -i "ab" data.doc #輸出所有含有ab或Ab的字符串的行
5.3 grep正則表達(dá)式的應(yīng)用 (注意:賊好把正則表達(dá)式用單引號(hào)括起來(lái))
grep '[239].' data.doc #輸出所有含有以2,3或9開(kāi)頭的,并且是兩個(gè)數(shù)字的行
不匹配測(cè)試:
grep '^[^48]' data.doc #不匹配行首是48的行
使用擴(kuò)展模式匹配:
grep -E '219|216' data.doc
顯示所有包含每個(gè)字符串至少有5個(gè)連續(xù)小寫字符的字符串的行:
$ grep '[a-z]{5}' aa
如果west被匹配,則es就被存儲(chǔ)到內(nèi)存中,并標(biāo)記為1,然后搜索任意個(gè)字符(.*),這些字符后面緊跟著 另外一個(gè)es(),找到就顯示該行。如果用egrep或grep -E,就不用””號(hào)進(jìn)行轉(zhuǎn)義,直接寫成’w(es)t.*′就可以了:
$ grep 'w(es)t.*1' aa
6.替換/查找/刪除命令——sed
6.1 sed語(yǔ)法
sed是一個(gè)很好的文件處理工具,本身是一個(gè)管道命令,主要是以行為單位進(jìn)行處理,可以將數(shù)據(jù)行進(jìn)行替換、刪除、新增、選取等特定工作,下面先了解一下sed的用法。sed命令行格式為:
sed [-nefri] ‘command’ 輸入文本
常用選項(xiàng):
-n∶使用安靜(silent)模式。在一般 sed 的用法中,所有來(lái)自 STDIN的資料一般都會(huì)被列出到螢?zāi)簧稀5绻由?-n 參數(shù)后,則只有經(jīng)過(guò)sed 特殊處理的那一行(或者動(dòng)作)才會(huì)被列出來(lái)。
-e∶直接在指令列模式上進(jìn)行 sed 的動(dòng)作編輯;
-f∶直接將 sed 的動(dòng)作寫在一個(gè)檔案內(nèi), -f filename 則可以執(zhí)行 filename 內(nèi)的sed 動(dòng)作;
-r∶sed 的動(dòng)作支援的是延伸型正規(guī)表示法的語(yǔ)法。(預(yù)設(shè)是基礎(chǔ)正規(guī)表示法語(yǔ)法)
-i∶直接修改讀取的檔案內(nèi)容,而不是由螢?zāi)惠敵觥?nbsp;
常用命令:
a ∶新增, a 的后面可以接字串,而這些字串會(huì)在新的一行出現(xiàn)(目前的下一行)~
c ∶取代, c 的后面可以接字串,這些字串可以取代 n1,n2 之間的行!
d ∶刪除,因?yàn)槭莿h除啊,所以 d 后面通常不接任何咚咚;
i ∶插入, i 的后面可以接字串,而這些字串會(huì)在新的一行出現(xiàn)(目前的上一行);
p ∶列印,亦即將某個(gè)選擇的資料印出。通常 p 會(huì)與參數(shù) sed -n 一起運(yùn)作~
s ∶取代,可以直接進(jìn)行取代的工作哩!通常這個(gè) s 的動(dòng)作可以搭配正規(guī)表示法!例如 1,20s/old/new/g 就是啦!
6.2 sed的使用
假設(shè)我們有一文件名為ab。
刪除某行:
# sed '1d' ab #刪除先進(jìn)行 # sed '$d' ab #刪除賊后一行 # sed '1,2d' ab #刪除先進(jìn)行到第二行 # sed '2,$d' ab #刪除第二行到賊后一行
顯示某行:
# sed -n '1p' ab #顯示先進(jìn)行 # sed -n '$p' ab #顯示賊后一行 # sed -n '1,2p' ab #顯示先進(jìn)行到第二行 # sed -n '2,$p' ab #顯示第二行到賊后一行
使用模式進(jìn)行查詢:
# sed -n '/ruby/p' ab #查詢包括關(guān)鍵字ruby所在所有行 # sed -n '/$/p' ab #查詢包括關(guān)鍵字$所在所有行,使用反斜線屏蔽特殊含義
增加一行或多行字符串:
# cat ab Hello! ruby is me,welcome to my blog. end # sed '1a drink tea' ab #先進(jìn)行后增加字符串"drink tea" Hello! drink tea ruby is me,welcome to my blog. end # sed '1,3a drink tea' ab #先進(jìn)行到第三行后增加字符串"drink tea" Hello! drink tea ruby is me,welcome to my blog. drink tea end drink tea # sed '1a drink tea or coffee' ab #先進(jìn)行后增加多行,使用換行符 Hello! drink tea or coffee ruby is me,welcome to my blog. end
代替一行或多行:
# sed '1c Hi' ab #先進(jìn)行代替為Hi Hi ruby is me,welcome to my blog. end # sed '1,2c Hi' ab #先進(jìn)行到第二行代替為Hi Hi end
替換一行中的某部分
格式:sed 's/要替換的字符串/新的字符串/g' (要替換的字符串可以用正則表達(dá)式)
# sed -n '/ruby/p' ab | sed 's/ruby/bird/g' #替換ruby為bird # sed -n '/ruby/p' ab | sed 's/ruby//g' #刪除ruby
插入:
# sed -i '$a bye' ab #在文件ab中賊后一行直接輸入"bye" # cat ab Hello! ruby is me,welcome to my blog. end bye
刪除匹配行:
sed -i '/匹配字符串/d' filename (注:若匹配字符串是變量,則需要“”,而不是‘’。記得好像是)
替換匹配行中的某個(gè)字符串:
sed -i '/匹配字符串/s/替換源字符串/替換目標(biāo)字符串/g' filename
7.強(qiáng)大的文本分析命令——awk
7.1 awk語(yǔ)法
awk是一個(gè)強(qiáng)大的文本分析工具,相對(duì)于grep的查找,sed的編輯,awk在其對(duì)數(shù)據(jù)分析并生成報(bào)告時(shí),顯得尤為強(qiáng)大。簡(jiǎn)單來(lái)說(shuō)awk就是把文件逐行的讀入,以空格為默認(rèn)分隔符將每行切片,切開(kāi)的部分再進(jìn)行各種分析處理。
awk '{pattern + action}' {filenames}
盡管操作可能會(huì)很復(fù)雜,但語(yǔ)法總是這樣,其中 pattern 表示 AWK 在數(shù)據(jù)中查找的內(nèi)容,而 action 是在找到匹配內(nèi)容時(shí)所執(zhí)行的一系列命令?;ɡㄌ?hào)({})不需要在程序中始終出現(xiàn),但它們用于根據(jù)特定的模式對(duì)一系列指令進(jìn)行分組。 pattern就是要表示的正則表達(dá)式,用斜杠括起來(lái)。
awk語(yǔ)言的賊基本功能是在文件或者字符串中基于指定規(guī)則瀏覽和抽取信息,awk抽取信息后,才能進(jìn)行其他文本操作。完整的awk腳本通常用來(lái)格式化文本文件中的信息。
通常,awk是以文件的一行為處理單位的。awk每接收文件的一行,然后執(zhí)行相應(yīng)的命令,來(lái)處理文本。
7.2 awk入門
假設(shè)last -n 5的輸出如下:
# last -n 5 # 僅取出前五行 root pts/1 192.168.1.100 Tue Feb 10 11:21 still logged in root pts/1 192.168.1.100 Tue Feb 10 00:46 - 02:28 (01:41) root pts/1 192.168.1.100 Mon Feb 9 11:41 - 18:30 (06:48) dmtsai pts/1 192.168.1.100 Mon Feb 9 11:41 - 11:41 (00:00) root tty1 Fri Sep 5 14:09 - 14:10 (00:01)
如果只是顯示賊近登錄的5個(gè)帳號(hào):
#last -n 5 | awk '{print $1}' root root root dmtsai root
awk工作流程是這樣的:讀入有' '換行符分割的一條記錄,然后將記錄按指定的域分隔符劃分域,填充域,$0則表示所有域,$1表示先進(jìn)個(gè)域,$n表示第n個(gè)域。默認(rèn)域分隔符是"空白鍵" 或 "[tab]鍵",所以$1表示登錄用戶,$3表示登錄用戶ip,以此類推。
如果只是顯示/jiyinjiance/jiaxue.txt的賬戶:
#cat /jiyinjiance/jiaxue.txt |awk -F ':' '{print $1}' root daemon bin sys
這種是awk+action的示例,每行都會(huì)執(zhí)行action{print $1}。
-F指定域分隔符為':'。
如果只是顯示/jiyinjiance/jiaxue.txt的賬戶和賬戶對(duì)應(yīng)的shell,而賬戶與shell之間以tab鍵分割:
#cat /jiyinjiance/jiaxue.txt |awk -F ':' '{print $1" "$7}' root /bin/bash daemon /bin/sh bin /bin/sh sys /bin/sh
如果只是顯示/jiyinjiance/jiaxue.txt的賬戶和賬戶對(duì)應(yīng)的shell,而賬戶與shell之間以逗號(hào)分割,而且在所有行添加列名name,shell,在賊后一行添加"blue,/bin/nosh":
#cat /jiyinjiance/jiaxue.txt |awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "blue,/bin/nosh"}' name,shell root,/bin/bash daemon,/bin/sh bin,/bin/sh sys,/bin/sh .... blue,/bin/nosh
awk工作流程是這樣的:先執(zhí)行BEGING,然后讀取文件,讀入有/n換行符分割的一條記錄,然后將記錄按指定的域分隔符劃分域,填充域,$0則表示所有域,$1表示先進(jìn)個(gè)域,$n表示第n個(gè)域,隨后開(kāi)始執(zhí)行模式所對(duì)應(yīng)的動(dòng)作action。接著開(kāi)始讀入第二條記錄······直到所有的記錄都讀完,賊后執(zhí)行END操作。
搜索/jiyinjiance/jiaxue.txt有root關(guān)鍵字的所有行:
#awk -F: '/root/{print $7}' /jiyinjiance/jiaxue.txt /bin/bash
這里指定了action{print $7}。
7.3 awk進(jìn)階
7.3.1 內(nèi)置變量
awk有許多內(nèi)置變量用來(lái)設(shè)置環(huán)境信息,這些變量可以被改變,下面給出了賊常用的一些變量。
ARGC 命令行參數(shù)個(gè)數(shù) ARGV 命令行參數(shù)排列 ENVIRON 支持隊(duì)列中系統(tǒng)環(huán)境變量的使用 FILENAME awk瀏覽的文件名 FNR 瀏覽文件的記錄數(shù) FS 設(shè)置輸入域分隔符,等價(jià)于命令行 -F選項(xiàng) NF 瀏覽記錄的域的個(gè)數(shù) NR 已讀的記錄數(shù) OFS 輸出域分隔符 ORS 輸出記錄分隔符 RS 控制記錄分隔符
此外,$0變量是指整條記錄。$1表示當(dāng)前行的先進(jìn)個(gè)域,$2表示當(dāng)前行的第二個(gè)域,......以此類推。
統(tǒng)計(jì)/jiyinjiance/jiaxue.txt:文件名,每行的行號(hào),每行的列數(shù),對(duì)應(yīng)的完整行內(nèi)容:
#awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /jiyinjiance/jiaxue.txt filename:/jiyinjiance/jiaxue.txt,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash filename:/jiyinjiance/jiaxue.txt,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/sh filename:/jiyinjiance/jiaxue.txt,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/sh filename:/jiyinjiance/jiaxue.txt,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh
使用printf替代print,可以讓代碼更加簡(jiǎn)潔,易讀:
#awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s ",FILENAME,NR,NF,$0)}' /jiyinjiance/jiaxue.txt
7.3.2 變量和賦值
除了awk的內(nèi)置變量,awk還可以自定義變量。
下面統(tǒng)計(jì)/jiyinjiance/jiaxue.txt的賬戶人數(shù):
#awk '{count++;print $0;} END{print "user count is ", count}' /jiyinjiance/jiaxue.txt root:x:0:0:root:/root:/bin/bash ...... user count is 40
count是自定義變量。之前的action{}里都是只有一個(gè)print,其實(shí)print只是一個(gè)語(yǔ)句,而action{}可以有多個(gè)語(yǔ)句,以;號(hào)隔開(kāi)。
這里沒(méi)有初始化count,雖然默認(rèn)是0,但是妥當(dāng)?shù)淖龇ㄟ€是初始化為0:
#awk 'BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}' /jiyinjiance/jiaxue.txt [start]user count is 0 root:x:0:0:root:/root:/bin/bash ... [end]user count is 40
7.3.3 條件語(yǔ)句
awk中的條件語(yǔ)句是從C語(yǔ)言中借鑒來(lái)的,用法與C語(yǔ)言一致。
統(tǒng)計(jì)某個(gè)文件夾下的文件占用的字節(jié)數(shù),過(guò)濾4096大小的文件(一般都是文件夾):
#ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}' [end]size is 8.22339 M
7.3.4 循環(huán)語(yǔ)句
awk中的循環(huán)語(yǔ)句同樣借鑒于C語(yǔ)言,支持while、do/while、for、break、continue,這些關(guān)鍵字的語(yǔ)義和C語(yǔ)言中的語(yǔ)義有效相同。
7.3.5 數(shù)組
因?yàn)閍wk中數(shù)組的下標(biāo)可以是數(shù)字和字母,數(shù)組的下標(biāo)通常被稱為關(guān)鍵字(key)。值和關(guān)鍵字都存儲(chǔ)在內(nèi)部的一張針對(duì)key/value應(yīng)用hash的表格里。由于hash不是順序存儲(chǔ),因此在顯示數(shù)組內(nèi)容時(shí)會(huì)發(fā)現(xiàn),它們并不是按照你預(yù)料的順序顯示出來(lái)的。數(shù)組和變量一樣,都是在使用時(shí)自動(dòng)創(chuàng)建的,awk也同樣會(huì)自動(dòng)判斷其存儲(chǔ)的是數(shù)字還是字符串。一般而言,awk中的數(shù)組用來(lái)從記錄中收集信息,可以用于計(jì)算總和、統(tǒng)計(jì)單詞以及跟蹤模板被匹配的次數(shù)等等。
顯示/jiyinjiance/jiaxue.txt的賬戶:
#awk -F ':' 'BEGIN {count=0;} {name[count] = $1;count++;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /jiyinjiance/jiaxue.txt 0 root 1 daemon 2 bin 3 sys 4 sync 5 games ......
這里使用for循環(huán)遍歷數(shù)組。