Unix文本處理工具之awk

Unix命令行下輸入的命令是文本翁垂,輸出也都是文本。因此,掌握Unix文本處理工具是很重要的一種能力。awk是Unix常用的文本處理工具中的一種方妖,它是以其發(fā)明者(Aho,Weinberger和Kernighan)的名字首字符命名的,是一種基于模式匹配檢查輸入然后將期望的匹配結果處理后輸出到屏幕的文本數據處理工具罚攀。

1党觅、awk命令格式

awk ‘模式 {操作}’ 文件1 文件2 ……

awk命令的工作過程是這樣的:對于每一個輸入文件,逐行對其進行檢查斋泄,如果該行和awk命令參數的‘模式’部分匹配杯瞻,則對該行執(zhí)行命令參數‘{操作}’部分所代表的操作。下面是一個簡單的例子:

$cat awk_test.txt
1 a a,b,d,f
2 b alsdjf,apple,kdjf
3 c 163.2.201.1
4 d www.google.com
5 e http://blog.csdn.net/xia7139
$awk 'NR==1{print}' awk_test.txt
1 a a,b,d,f

上面的例子中炫掐,用awk命令輸出了awk_test.txt文件的第一行魁莉,其中命令的模式部分所用的NR是awk命令的內建變量,代表文件的行號募胃。這樣旗唁,便可以對所有行號為1的行進行打印輸出。

2痹束、語法說明

2.1 常用的內建變量

變量 含義
NR 當前處理行的行號
FS 字段分隔检疫,默認為空格或TAB
$n 當前處理行的第n個字段
$0 當前處理行的全部內容
$NF 表示當前處理行的最后一個字段

這里要解釋下字段的含義:在awk的使用中,字段分隔符將文件的一行分隔為各個部分参袱,每一個部分稱為一個字段电谣,從左到右分別為第1個字段秽梅,……,第n個字段剿牺,其中企垦,第0個字段是指這一整行。字段分隔符如果沒有特殊指定晒来,則默認為空格或tab制表符钞诡。

2.2 在字段中匹配

awk可以支持根據特定字段內容的匹配,操作符是~湃崩。該操作符的否定是!~荧降,表示不匹配。下面是幾個例子:

  • 輸出第三個字段包含a的行攒读。

      $ awk '$3 ~ /a/ {print}' awk_test.txt 
      1 a a,b,d,f
      2 b alsdjf,apple,kdjf
      5 e http://blog.csdn.net/xia7139
    
  • 輸出第三個字段不包含a的行

      $ awk '$3 !~ /a/ {print}' awk_test.txt 
      3 c 163.2.201.1
      4 d www.google.com
    

2.3 awk變量

awk命令是支持變量的朵诫,定義變量的選項是-v,下面是一個例子薄扁。

  • 打印第二個字段包含b的行

      $ var=b
      $ awk -v x=$var '$2 ~ x{print}' awk_test.txt 
      2 b alsdjf,apple,kdjf
    
  • 打印第二個字段不包含b的行

      $ var=b
      $ awk -v x=$var '$2 !~ x{print}' awk_test.txt 
      1 a a,b,d,f
      3 c 163.2.201.1
      4 d www.google.com
      5 e http://blog.csdn.net/xia7139
    

但是剪返,變量在//中不起作用:

$ var=b
$ awk -v x=$var '$3 ~ /x/{print}' awk_test.txt 
5 e http://blog.csdn.net/xia7139

可以認為awk -v x=$var '$2 ~ x{print}' awk_test.txt就相當于awk '$2 ~ /b/{print}' awk_test.txt,也就是說會將變量的值當作正則表達式匹配。下面的例子可以說明這個問題:

$ var=.
$ awk -v x=$var '$3 ~ x{print}' awk_test.txt 
1 a a,b,d,f
2 b alsdjf,apple,kdjf
3 c 163.2.201.1
4 d www.google.com
5 e http://blog.csdn.net/xia7139

$ var=\\\\.
$ awk -v x=$var '$3 ~ x{print}' awk_test.txt 
3 c 163.2.201.1
4 d www.google.com
5 e http://blog.csdn.net/xia7139

2.4 awk默認的行分隔符和列分隔符

awk中有兩個特殊的變量ORS和OFS分別記錄著其缺省的行分隔符邓梅,ORS的默認值為換行\n脱盲,OFS的默認值為空格。因此日缨,默認的awk會用它們來分隔行和列钱反。下面是幾個例子:

  • 當我們試圖用=分隔各個字段時

      $ awk '{print $1,"=",$2,"=",$3}' awk_test.txt 
      1 = a = a,b,d,f
      2 = b = alsdjf,apple,kdjf
      3 = c = 163.2.201.1
      4 = d = www.google.com
      7 = d = www.google.com
      4 = d = www.googlecom
      5 = e = http://blog.csdn.net/xia7139
    

    可以看到,這樣=被作為awk的一個字段輸出匣距,和其它字段之間用空格隔開面哥,實際上相當于"?=?"作為了分隔符分隔了各個原來的字段。

  • 只用=分隔各個字段

    這時候就需要將OFS置為空字符串毅待,如下:

      $ awk 'BEGIN{OFS=""}{print $1,"=",$2,"=",$3}' awk_test.txt 
      1=a=a,b,d,f
      2=b=alsdjf,apple,kdjf
      3=c=163.2.201.1
      4=d=www.google.com
      7=d=www.google.com
      4=d=www.googlecom
      5=e=http://blog.csdn.net/xia7139
    
  • 同理幢竹,可實現在行與行之間添加空行

      $ awk 'BEGIN{ORS="\n\n"}{print $1,"=",$2,"=",$3}' awk_test.txt | head -n 5
      1 = a = a,b,d,f
      
      2 = b = alsdjf,apple,kdjf
      
      3 = c = 163.2.201.1
    

2.5 awk中的BEGIN和END

BEGIN作用是執(zhí)行一些初始化操作,END的作用是程序結束后執(zhí)行掃尾的工作恩静。

任何在BEGIN之后列出的操作(在{}內)將在Unix awk開始掃描輸入之前執(zhí)行,而END之后列出的操作將在掃描完全部的輸入之后執(zhí)行蹲坷。因此驶乾,通常使用BEGIN來顯示變量和預置(初始化)變量,使用END來輸出最終結果循签。

下面是一個例子:

$ awk 'BEGIN{product=1}{print $1,"=",$2,"=",$3;product=product*$1}END{printf "product: %.3f\n",product}' awk_test.txt
1 = a = a,b,d,f
2 = b = alsdjf,apple,kdjf
3 = c = 163.2.201.1
4 = d = www.google.com
7 = d = www.google.com
4 = d = www.googlecom
5 = e = http://blog.csdn.net/xia7139
product: 3360.000
$ 

3级乐、幾個例子及其輸出

3.1 下面的例子都是對上文中的awk_test.txt文件的操作

3.1.1 按行號操作

  • 打印文件的1-3行

      $awk 'NR==1,NR==3{print}' awk_test.txt
      1 a a,b,d,f
      2 b alsdjf,apple,kdjf
      3 c 163.2.201.1
    
  • 打印文件的第1行和第3行

      $awk 'NR==1||NR==3{print}' awk_test.txt
      或者是
      $awk '(NR==1)||(NR==3){print}' awk_test.txt
      1 a a,b,d,f
      3 c 163.2.201.1
    
  • 只打印奇數行(偶數行)

      $awk '(NR%2)==1{print}' awk_test.txt
      1 a a,b,d,f
      3 c 163.2.201.1
      5 e http://blog.csdn.net/xia7139
      $awk '(NR%2)==0{print}' awk_test.txt
      2 b alsdjf,apple,kdjf
      4 d www.google.com
    

3.1.2 使用正則表達式

  • 打印包含2的行

      $awk '/2/{print}' awk_test.txt
      2 b alsdjf,apple,kdjf
      3 c 163.2.201.1
    
  • 打印以com結尾的行

      $awk '/com$/{print}' awk_test.txt
      4 d www.google.com
    

3.1.3 指定分隔,輸出指定字段

  • 打印第1-3行的第一個字段和第三個字段

      $awk 'NR==1,NR==3{print $1,$3}' awk_test.txt
      1 a,b,d,f
      2 alsdjf,apple,kdjf
      3 163.2.201.1
    
  • 指定分隔符為.县匠,輸出第二個字段為csdn的行的第三個字段和整行

      $awk -F. '$2=="csdn"{print $3,$0}' awk_test.txt
      net/xia7139 5 e http://blog.csdn.net/xia7139
    
  • 指定分隔符為.风科,輸出每行的最后一個字段

      $ awk -F. '{print $NF}' awk_test.txt 
      1 a a,b,d,f
      2 b alsdjf,apple,kdjf
      1
      com
      net/xia7139
    

3.2 awk對文件中的行按重復次數排序

下面的文件是從數據庫中導出的一些數據(一部分)撒轮,但是后續(xù)發(fā)現有些字段不需要。而如果重新從數據庫中導出生成的話贼穆,耗費的時間太長题山,這里就用到了awk命令了。

文件test.txt的內容如下故痊,每行有三個字段顶瞳,字段之間用“ ::: ”隔開:

11 ::: Thomas R. Dean ::: 54
14 ::: Johann van Rensburg ::: 1
75 ::: Arun G. Phadke ::: 13
81 ::: Tiffany M. Frazier ::: 2
84 ::: Sridhar R. Iyer ::: 1
95 ::: Leesa Murray ::: 11
96 ::: David S. Munro ::: 34
104 ::: David R. Lovell ::: 2
112 ::: Steffen Rusitschka ::: 3
161 ::: Peter Forbrig ::: 116

現在想只取出第后面的兩個字段去掉前面的字段:

$ awk -F :::  '{print $2,$3}' test.txt
 Thomas R. Dean   54
 Johann van Rensburg   1
 Arun G. Phadke   13
 Tiffany M. Frazier   2
 Sridhar R. Iyer   1
 Leesa Murray   11
 David S. Munro   34
 David R. Lovell   2
 Steffen Rusitschka   3
 Peter Forbrig   116

發(fā)現前面有多余的不想要的空格,一點都不優(yōu)雅愕秫。原來-F指定的分隔符是要將空格轉義才能生效慨菱。

$ awk -F\ :::\  '{print $2,$3}' test.txt
Thomas R. Dean 54
Johann van Rensburg 1
Arun G. Phadke 13
Tiffany M. Frazier 2
Sridhar R. Iyer 1
Leesa Murray 11
David S. Munro 34
David R. Lovell 2
Steffen Rusitschka 3
Peter Forbrig 116

這樣就好多了,但是戴甩,現在又想將上面的兩個字段還是用原來的“ ::: ”隔開符喝。

$ awk -F\ :::\  '{print $2,":::",$3}' test.txt
Thomas R. Dean ::: 54
Johann van Rensburg ::: 1
Arun G. Phadke ::: 13
Tiffany M. Frazier ::: 2
Sridhar R. Iyer ::: 1
Leesa Murray ::: 11
David S. Munro ::: 34
David R. Lovell ::: 2
Steffen Rusitschka ::: 3
Peter Forbrig ::: 116

Wow, it is beautiful!
下面如果發(fā)現有重復的話,可以進行進一步的去重甜孤。這里隨意生成了一個有重復的test.txt來進行操作协饲,其內容如下:

11 ::: Thomas R. Dean ::: 54
1411 ::: Johann van Rensburg ::: 1
106 ::: Peter Forbrig ::: 116 
141 ::: Johann van Rensburg ::: 1
143 ::: Johann van Rensburg ::: 1
75 ::: Arun G. Phadke ::: 13
844 ::: Sridhar R. Iyer ::: 1
149 ::: Johann van Rensburg ::: 1
81 ::: Tiffany M. Frazier ::: 2
84 ::: Sridhar R. Iyer ::: 1
95 ::: Leesa Murray ::: 11
96 ::: David S. Munro ::: 34
104 ::: David R. Lovell ::: 2
15 ::: Johann van Rensburg ::: 1
112 ::: Steffen Rusitschka ::: 3
12 ::: Steffen Rusitschka ::: 3
161 ::: Peter Forbrig ::: 116 
106 ::: Peter Forbrig ::: 116

首先對awk生成的結果排序:

$ awk -F\ :::\  '{print $2,":::",$3}' test.txt | sort
Arun G. Phadke ::: 13
David R. Lovell ::: 2
David S. Munro ::: 34
Johann van Rensburg ::: 1
Johann van Rensburg ::: 1
Johann van Rensburg ::: 1
Johann van Rensburg ::: 1
Johann van Rensburg ::: 1
Leesa Murray ::: 11
Peter Forbrig ::: 116
Peter Forbrig ::: 116
Peter Forbrig ::: 116
Sridhar R. Iyer ::: 1
Sridhar R. Iyer ::: 1
Steffen Rusitschka ::: 3
Steffen Rusitschka ::: 3
Thomas R. Dean ::: 54
Tiffany M. Frazier ::: 2

然后,進行去重课蔬,之所以進行排序囱稽,是因為uniq命令只能對相鄰行進行去重。

$ awk -F\ :::\  '{print $2,":::",$3}' test.txt | sort | uniq 
Arun G. Phadke ::: 13
David R. Lovell ::: 2
David S. Munro ::: 34
Johann van Rensburg ::: 1
Leesa Murray ::: 11
Peter Forbrig ::: 116
Sridhar R. Iyer ::: 1
Steffen Rusitschka ::: 3
Thomas R. Dean ::: 54
Tiffany M. Frazier ::: 2

如果需要根據重復次數排序二跋,可以用“awk -F\ :::\ '{print $2,":::",$3}' test.txt | sort | uniq -c | sort -rn”這里sort的-n選項是指定根據每行第一個字段的數字值的大小排序战惊,比如30比4大,如果沒有-n那么就是默認字典序排扎即,4比30大吞获。而unique中的-c選項是指定在每行之前加一個重復次數字段。
這里為了排序用sort -n先將數字字段放到前面谚鄙,然后排序各拷,排完之后,再將數字字段放到后面(實際上闷营,可以用更加優(yōu)雅的方法烤黍,直接指定按第二個字段排序就可以,這里用的是先顛過來傻盟,然后再倒回去的方法速蕊。

$ awk -F\ :::\  '{print $3,":::",$2}' test.txt | sort | uniq | sort -rn | awk -F\ :::\  '{print $2,":::",$1}'
Peter Forbrig ::: 116
Thomas R. Dean ::: 54
David S. Munro ::: 34
Arun G. Phadke ::: 13
Leesa Murray ::: 11
Steffen Rusitschka ::: 3
Tiffany M. Frazier ::: 2
David R. Lovell ::: 2
Sridhar R. Iyer ::: 1
Johann van Rensburg ::: 1

3.3 awk命令將文本文件中的數字相加

這里有一個文本文件,其中娘赴,每行的第二個字段是一個數字规哲,現在想要將每行的數字加起來,應該如何操作呢诽表?下面給出awk命令的版本:

$ cat awk_sum_test.txt
apple 1
google 2
sammung 3
moto 4
xiaomi 5
smartisan 6
oppo 7
huawei 8
coolpad 9
lenevo 10
$ awk '{sum+=$2}END{print sum}' awk_sum_test.txt 
55
$ 

從這個命令可以看出唉锌,awk命令的使用還是比較方便的隅肥。初次之外,要知道awk命令的語法十分復雜袄简,上面說到的只是很少的一部分腥放。從這個例子中的用法來看,我們也能夠知道前面提到的awk命令的基本格式awk ‘模式 {操作}’ 文件1 文件2 ……中的痘番,'模式 {操作}'單位實際上捉片,是可以有多個的,也就是說可以是awk ‘模式 {操作}模式 {操作}... ...’ 文件1 文件2 ……汞舱。awk會逐個檢查每個模式伍纫,然后對符合模式的行執(zhí)行相應的操作。下面是一個例子:

$ awk '{sum+=$2}NR <5 1{print $1}END{print sum}' awk_sum_test.txt    
apple
google
sammung
moto
xiaomi
lenevo
55
$ 

實際上昂芜,這個例子中的問題也可以用linux shell下讀取文件的方法來解決莹规,只不過稍微有點麻煩。關于awk命令泌神,個人認為只能是邊用邊學良漱,以后遇到比較好的例子,還會貼在在這里欢际。_

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末母市,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子损趋,更是在濱河造成了極大的恐慌患久,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浑槽,死亡現場離奇詭異蒋失,居然都是意外死亡,警方通過查閱死者的電腦和手機桐玻,發(fā)現死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門篙挽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人镊靴,你說我怎么就攤上這事铣卡。” “怎么了偏竟?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵算行,是天一觀的道長。 經常有香客問我苫耸,道長,這世上最難降的妖魔是什么儡陨? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任褪子,我火速辦了婚禮量淌,結果婚禮上,老公的妹妹穿的比我還像新娘嫌褪。我一直安慰自己呀枢,他們只是感情好,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布笼痛。 她就那樣靜靜地躺著裙秋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪缨伊。 梳的紋絲不亂的頭發(fā)上摘刑,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音刻坊,去河邊找鬼枷恕。 笑死,一個胖子當著我的面吹牛谭胚,可吹牛的內容都是我干的徐块。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼灾而,長吁一口氣:“原來是場噩夢啊……” “哼胡控!你這毒婦竟也來了?” 一聲冷哼從身側響起旁趟,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤昼激,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后轻庆,有當地人在樹林里發(fā)現了一具尸體癣猾,經...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年余爆,在試婚紗的時候發(fā)現自己被綠了纷宇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛾方,死狀恐怖像捶,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情桩砰,我是刑警寧澤拓春,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站亚隅,受9級特大地震影響硼莽,放射性物質發(fā)生泄漏。R本人自食惡果不足惜煮纵,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一懂鸵、第九天 我趴在偏房一處隱蔽的房頂上張望偏螺。 院中可真熱鬧,春花似錦匆光、人聲如沸套像。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽夺巩。三九已至,卻和暖如春周崭,著一層夾襖步出監(jiān)牢的瞬間柳譬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工休傍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留征绎,地道東北人。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓磨取,卻偏偏與公主長得像人柿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子忙厌,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內容

  • 轉載 原文的排版和內容都更加友好,并且詳細,我只是在這里貼出了一部分留作自己以后參考和學習,如希望更詳細了解AWK...
    XKirk閱讀 3,214評論 2 25
  • 本章主要學習內容awk介紹 ?awk基本用法 ?awk變量 ?awk格式化 ?awk操作符 ?awk條件判斷 ?a...
    楠人幫閱讀 1,269評論 0 8
  • awk介紹awk變量printf命令:實現格式化輸出操作符awk patternawk actionawk數組aw...
    哈嘍別樣閱讀 1,564評論 0 4
  • netstat -tnlp|egrep -i "$1"|awk {'print $7'}|awk -F'/' '{...
    JerichoYu閱讀 1,008評論 0 0
  • 1甥雕、Nginx日志分析日志格式:'$remote_addr - $remote_user [$time_local...
    運維前線閱讀 717評論 0 4