使用 Unix 進(jìn)行文本處理

正則表達(dá)式

翻譯領(lǐng)域不乏讓人摸不著頭腦的詞匯熊昌,比如“句柄”绽榛、“套接字”、“魯棒性”婿屹。當(dāng)然灭美,“正則表達(dá)式”也屬于這一類詞匯。我剛接觸正則表達(dá)式的時(shí)候昂利,對(duì)這個(gè)名詞感到非常迷惑届腐。深入了解之后,才突然明白蜂奸,原來(lái)所謂的 regular expression犁苏, 其實(shí)就是“有規(guī)律、有模式的字符串”而已扩所。

很少有一門技術(shù)围详,只需要投入少量的學(xué)習(xí)成本即可獲得巨大的價(jià)值回報(bào)。正則表達(dá)式就屬于這一類技術(shù)碌奉《淘可惜很多人被它密碼般的語(yǔ)法形式當(dāng)頭棒喝,甚至連門都不得而入赐劣。

為什么你應(yīng)該學(xué)習(xí)正則表達(dá)式?其一哩都,在實(shí)踐中應(yīng)用這門技術(shù)其實(shí)不難魁兼,只需理解為數(shù)不多的幾個(gè)元字符以及并不復(fù)雜的語(yǔ)法,就能夠獲得強(qiáng)大的文本操控能力漠嵌;其二咐汞,正則表達(dá)式往往能提供處理文本的最簡(jiǎn)單最高效的解決方法(有時(shí)也許是唯一的解法)。遇上復(fù)雜的情況儒鹿,如果你不會(huì)正則表達(dá)式化撕,就只好束手無(wú)策、黯然神傷了约炎。

正則表達(dá)式入門容易植阴,精通卻難。本文并不打算挑戰(zhàn)此項(xiàng)任務(wù)圾浅,如果你希望系統(tǒng)地學(xué)習(xí)正則表達(dá)式掠手,請(qǐng)一定閱讀 Jeffrey Friedl 的著作 精通正則表達(dá)式

regex.png

文本檢索

grep 命令可以完成簡(jiǎn)單的文本搜索任務(wù)狸捕。

先來(lái)準(zhǔn)備一份文本材料喷鸽,把 grep 的幫助頁(yè)保存為文本文件:

> man grep | col -b > grephelp.txt

下面,我想檢索 grephelp.txt 文件中所有包含 "find" 這個(gè)單詞的文本行:

> grep "find" grephelp.txt
     To find all occurrences of the word `patricia' in a file:
     To find all occurrences of the pattern `.Pp' at the beginning of a line:
     To find all lines in a file which do not contain the words `foo' or

我希望匹配到的文本使用不同的顏色顯示灸拍,可以添加 --color 選項(xiàng)做祝,默認(rèn)的顏色是紅色砾省。

> grep --color "find" grephelp.txt

我希望在匹配結(jié)果中顯示文件名和行號(hào),使用 -H 選項(xiàng)可以顯示文件名混槐,使用 -n 選項(xiàng)可以顯示行號(hào):

> grep -H -n --color "find" grephelp.txt
grephelp.txt:252:     To find all occurrences of the word `patricia' in a file:
grephelp.txt:256:     To find all occurrences of the pattern `.Pp' at the beginning of a line:
grephelp.txt:265:     To find all lines in a file which do not contain the words `foo' or

很多時(shí)候编兄,我們需要知道匹配行前后的上下文。-A-B 這兩個(gè)選項(xiàng)會(huì)是你的好朋友纵隔。-A n 表示顯示匹配行以及其后的 n 行翻诉;-B n 表示顯示匹配行以及之前的 n 行。現(xiàn)在捌刮,我們?cè)谄ヅ湫械那昂蠓謩e額外顯示兩行:

> grep -A 2 -B 2 -H -n --color "find" grephelp.txt
grephelp.txt-250-
grephelp.txt-251-EXAMPLES
grephelp.txt:252:     To find all occurrences of the word `patricia' in a file:
grephelp.txt-253-
grephelp.txt-254-      $ grep 'patricia' myfile
--
--
grephelp.txt-254-      $ grep 'patricia' myfile
grephelp.txt-255-
grephelp.txt:256:     To find all occurrences of the pattern `.Pp' at the beginning of a line:
grephelp.txt-257-
grephelp.txt-258-      $ grep '^\.Pp' myfile
--
--
grephelp.txt-263-     match any character.
grephelp.txt-264-
grephelp.txt:265:     To find all lines in a file which do not contain the words `foo' or
grephelp.txt-266-     `bar':
grephelp.txt-267-

如果需要查找所有不包含 "find" 的文本行碰煌,該怎么做呢?很簡(jiǎn)單绅作,使用 -v 選項(xiàng)即可芦圾。

grep 還有兩個(gè)變體,egrep 和 fgrep俄认。相對(duì)于僅支持基本正則模式(BREs)的 grep 來(lái)說(shuō)个少,egrep 支持?jǐn)U展正則模式(EREs),因而檢索能力更為強(qiáng)大眯杏;fgrep 是所有三個(gè)工具中速度最快的一個(gè)夜焦,因?yàn)樗耆恢С终齽t模式。

其實(shí)岂贩,我更喜歡一個(gè)叫做 ack 的工具茫经。

ack

文本替換

tr 命令可以完成簡(jiǎn)單的字符轉(zhuǎn)換任務(wù)。例如萎津,可以通過(guò) tr 把 grephelp.txt 文件轉(zhuǎn)換為全文大寫:

> cat grephelp.txt | tr '[:lower:]' '[:upper:]'

簡(jiǎn)而言之卸伞,tr 的工作就是把第一個(gè)集合中的字符轉(zhuǎn)換為第二個(gè)集合中的相應(yīng)的字符。常用的字符集合有下面這些:

  • [:alnum:]:字母數(shù)字
  • [:alpha:]:字母
  • [:cntrl:] :控制字符
  • [:digit:]:數(shù)字
  • [:graph:]: 圖形字符
  • [:lower:]:小寫字母
  • [:print:]:可打印字符
  • [:punct:]:標(biāo)點(diǎn)符號(hào)
  • [:space:]:空白字符
  • [:upper:]:大寫字母
  • [:xdigit:]:十六進(jìn)制數(shù)字

tr 命令的應(yīng)用場(chǎng)景非常受限锉屈,如果希望進(jìn)行更加靈活的模式替換荤傲,我們還有 sed(也就是 stream editor,流編輯器)颈渊。

把文件中所有的 "find" 文本替換為 "search":

> sed "s/find/search/g" grephelp.txt

這條命令中遂黍,s 表示執(zhí)行“替換操作”,/find/search/ 表示把 "find" 替換為 "search"儡炼,g 表示對(duì)一行中所有的匹配進(jìn)行替換妓湘。sed 默認(rèn)把處理結(jié)果打印到標(biāo)準(zhǔn)輸出,我們可以通過(guò)重定向把處理結(jié)果轉(zhuǎn)儲(chǔ)到一個(gè)新文件中乌询,或者使用選項(xiàng) -i 把結(jié)果直接寫回原文件(有風(fēng)險(xiǎn)榜贴,需謹(jǐn)慎):

> sed -i "s/find/search/g" grephelp.txt

把文件中所有的數(shù)字 n 替換為 "--n--" 的形式:

> sed -E "s/([0-9]+)/--\1--/g" grephelp.txt

選項(xiàng) -E 表示在處理過(guò)程中使用擴(kuò)展的正則模式(EREs),替換命令中的 \1 表示引用正則表達(dá)式的第一個(gè)捕獲分組。請(qǐng)注意唬党,-E 這個(gè)選項(xiàng)只在 Mac OS X 系統(tǒng)和 FreeBSD 系統(tǒng)上有效鹃共,其他 Unix 系統(tǒng)需要使用另一個(gè)等效的選項(xiàng) -r

sed 的功能遠(yuǎn)不止這一些驶拱,篇幅所限霜浴,不可能詳細(xì)講解 sed 的用法。如果希望學(xué)習(xí)更多蓝纲,請(qǐng)移步這篇文章阴孟。

文本去重

> cat -n sonnet116.txt
     1  Let me not to the marriage of true minds
     2  Admit impediments. Love is not love
     3  Which alters when it alteration finds,
     4  Or bends with the remover to remove:
     5  O, no! it is an ever-fix`ed mark,
     6  O, no! it is an ever-fix`ed mark,
     7  That looks on tempests and is never shaken;
     8  It is the star to every wand'ring bark,
     9  Whose worth's unknown, although his heighth be taken.
    10  Love's not Time's fool, though rosy lips and cheeks
    11  Love's not Time's fool, though rosy lips and cheeks
    12  Love's not Time's fool, though rosy lips and cheeks
    13  Within his bending sickle's compass come;
    14  Love alters not with his brief hours and weeks,
    15  But bears it out even to the edge of doom:
    16  If this be error and upon me proved,
    17  I never writ, nor no man ever loved.

這是莎士比亞的一首十四行詩(shī),只可惜第5行和第10行有重復(fù)(而且第10行重復(fù)了3次)税迷。怎么查看文本中重復(fù)的行呢永丝?uniq 命令可以幫助你。

> uniq -d sonnet116.txt
O, no! it is an ever-fix`ed mark,
Love's not Time's fool, though rosy lips and cheeks

選項(xiàng) -d 表示僅輸出重復(fù)的行箭养。如果需要去重慕嚷,使用不帶選項(xiàng)的 uniq 命令就可以了:

> uniq sonnet116.txt
Let me not to the marriage of true minds
Admit impediments. Love is not love
Which alters when it alteration finds,
Or bends with the remover to remove:
O, no! it is an ever-fix`ed mark,
That looks on tempests and is never shaken;
It is the star to every wand'ring bark,
Whose worth's unknown, although his heighth be taken.
Love's not Time's fool, though rosy lips and cheeks
Within his bending sickle's compass come;
Love alters not with his brief hours and weeks,
But bears it out even to the edge of doom:
If this be error and upon me proved,
I never writ, nor no man ever loved.

想要查看每一行究竟重復(fù)了多少次?沒(méi)問(wèn)題毕泌,使用選項(xiàng) -c

> uniq -c sonnet116.txt
   1 Let me not to the marriage of true minds
   1 Admit impediments. Love is not love
   1 Which alters when it alteration finds,
   1 Or bends with the remover to remove:
   2 O, no! it is an ever-fix`ed mark,
   1 That looks on tempests and is never shaken;
   1 It is the star to every wand'ring bark,
   1 Whose worth's unknown, although his heighth be taken.
   3 Love's not Time's fool, though rosy lips and cheeks
   1 Within his bending sickle's compass come;
   1 Love alters not with his brief hours and weeks,
   1 But bears it out even to the edge of doom:
   1 If this be error and upon me proved,
   1 I never writ, nor no man ever loved.

文本排序

假設(shè)有這樣一個(gè)報(bào)表文件喝检,第一列是月份,第二列是當(dāng)月的銷售個(gè)數(shù):

> cat report.txt
March,19
June,50
February,17
May,18
August,16
April,31
May,18
July,26
January,24
August,16

這個(gè)文件的內(nèi)容不僅順序是亂的撼泛,而且還有重復(fù)挠说。我希望按字母表順序排序,可以下面這個(gè)命令:

> sort report.txt
April,31
August,16
August,16
February,17
January,24
July,26
June,50
March,19
May,18
May,18

選項(xiàng) -u (表示 unique)可以在排序結(jié)果中去除重復(fù)行:

> sort -u report.txt
April,31
August,16
February,17
January,24
July,26
June,50
March,19
May,18

能不能按照月份排序呢愿题?選項(xiàng) -M (表示 month-sort)可以幫助我們:

> sort -u -M report.txt
January,24
February,17
March,19
April,31
May,18
June,50
July,26
August,16

按照第二列的數(shù)字進(jìn)行排序也是很簡(jiǎn)單的:

> sort -u -t',' -k2 report.txt
August,16
February,17
May,18
March,19
January,24
July,26
April,31
June,50

上面的例子中纺涤,選項(xiàng) -t',' 表示以逗號(hào)為分隔符對(duì)文本進(jìn)行列分割;-k2 表示對(duì)第2列進(jìn)行排序抠忘。

當(dāng)然了,把結(jié)果逆序排列也并非不可能:

> sort -u -r -t',' -k2 report.txt
June,50
April,31
July,26
January,24
March,19
May,18
February,17
August,16

文本統(tǒng)計(jì)

wc 命令用來(lái)完成文本統(tǒng)計(jì)工作外永,通過(guò)使用不同的選項(xiàng)崎脉,它可以統(tǒng)計(jì)文件中的字節(jié)數(shù)(-c),字符數(shù)(-m)伯顶,單詞數(shù)(-w)與行數(shù)(-l)囚灼。

例如,查看 grephelp.txt 這個(gè)文件總共有多少個(gè)單詞:

> wc -w grephelp.txt
    1571 grephelp.txt

查看 sonnet116.txt 這個(gè)文件總共有多少不重復(fù)的行(廢話祭衩,十四行詩(shī)當(dāng)然是有14行):

> uniq sonnet116.tx6 | wc -l
      14

你還應(yīng)該試試 Awk 與 Perl

如果上面介紹的工具仍然不能滿足你灶体,也許你需要火力更強(qiáng)的武器。試試 Awk 與 Perl 吧掐暮。

Awk 也是一款上古神器蝎抽,它的年齡可能和 sed 不相上下。Awk 可謂是專門為了文本處理而生路克,它的語(yǔ)法和特性非常適合用于操縱文本和生成報(bào)表樟结。如需學(xué)習(xí)养交,請(qǐng)參考 這篇文章,你會(huì)喜歡上它的瓢宦。

長(zhǎng)久以來(lái)碎连,Perl 背負(fù)了“只寫語(yǔ)言”的惡名。實(shí)際上驮履,只要處理得當(dāng)鱼辙,用 Perl 一樣可以寫出模塊清晰的、容易閱讀和理解的代碼玫镐。根據(jù)我的經(jīng)驗(yàn)倒戏,使用 Perl 的場(chǎng)合 80% 以上與文本處理有關(guān)。Perl 內(nèi)置的正則表達(dá)式支持可能是所有語(yǔ)言中最好的摘悴,再加上簡(jiǎn)潔緊湊的語(yǔ)法以及便利的操作符峭梳,這些特性幫助 Perl 成了文本處理領(lǐng)域當(dāng)仁不讓的霸主。

圖片來(lái)自 xkcd.com
圖片來(lái)自 xkcd.com
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蹂喻,一起剝皮案震驚了整個(gè)濱河市葱椭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌口四,老刑警劉巖孵运,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蔓彩,居然都是意外死亡治笨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門赤嚼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)旷赖,“玉大人,你說(shuō)我怎么就攤上這事更卒〉确酰” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵蹂空,是天一觀的道長(zhǎng)俯萌。 經(jīng)常有香客問(wèn)我,道長(zhǎng)上枕,這世上最難降的妖魔是什么咐熙? 我笑而不...
    開封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮辨萍,結(jié)果婚禮上棋恼,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好蘸泻,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開白布琉苇。 她就那樣靜靜地躺著,像睡著了一般悦施。 火紅的嫁衣襯著肌膚如雪并扇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天抡诞,我揣著相機(jī)與錄音穷蛹,去河邊找鬼。 笑死昼汗,一個(gè)胖子當(dāng)著我的面吹牛肴熏,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顷窒,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蛙吏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了鞋吉?” 一聲冷哼從身側(cè)響起鸦做,我...
    開封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谓着,沒(méi)想到半個(gè)月后泼诱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赊锚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年治筒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舷蒲。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耸袜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牲平,到底是詐尸還是另有隱情句灌,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布欠拾,位于F島的核電站,受9級(jí)特大地震影響骗绕,放射性物質(zhì)發(fā)生泄漏藐窄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一酬土、第九天 我趴在偏房一處隱蔽的房頂上張望荆忍。 院中可真熱鬧,春花似錦、人聲如沸刹枉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)微宝。三九已至棺亭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蟋软,已是汗流浹背镶摘。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留岳守,地道東北人凄敢。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像湿痢,于是被迫代替她去往敵國(guó)和親涝缝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 知識(shí)點(diǎn) sort uniq cut wc sed命令 awk命令 crontab定時(shí)器 sort sort 命令對(duì)...
  • Unix 進(jìn)行文本處理 正則表達(dá)式 翻譯領(lǐng)域不乏讓人摸不著頭腦的詞匯譬重,比如“句柄”拒逮、“套接字”、“魯棒性”害幅。當(dāng)然消恍,...
    鮑陳飛閱讀 767評(píng)論 0 1
  • 本文承接之前寫的三十分鐘學(xué)會(huì)AWK一文,在學(xué)習(xí)完AWK之后以现,趁熱打鐵又學(xué)習(xí)了一下SED狠怨,不得不說(shuō)這兩個(gè)工具真的堪稱...
    mylxsw閱讀 4,401評(píng)論 3 74
  • sed與awk實(shí)例 文本間隔 在每一行后面增加一空行 將原來(lái)的所有空行刪除并在每一行后面增加一空行。這樣在輸出的文...
    stuha閱讀 1,901評(píng)論 0 21
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯(cuò)誤還是無(wú)法避免 以后資料會(huì)慢慢更新 大...
    數(shù)據(jù)革命閱讀 12,175評(píng)論 2 33