awk文本處理

1、前言

(一)、awk簡介

  awk是一種編程語言,用於在linux/unix下對文本和數據進行處理,數據能夠來自標準輸入、一個或多個文件,或其它命令的輸出,它支持用戶自定義函數和動態正則表達式等先進功能,是linux/unix下的一個強大編程工具,它在命令行中使用,但更多的是做爲腳原本使用;linux

  awk 的處理文本和數據的方式是這樣的,它逐行掃描文件,從第一行到最後一行,尋找匹配的尋找匹配的特定模式的行,並在這些行上進行你想要的操做,若是沒有指定處理動做,則把匹配的行顯示到標準輸出(屏幕),若是沒有指定模式,則全部被操做所指定的行都被處理;nginx

  awk 分別表明其做者是三我的,分別是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell實驗和GNU的一些擴展。正則表達式

(二)、awk語法格式

awk [options] 'commands' filenames awk [options] -f awk-script-file filenames

①、options:shell

-F          定義輸入字段分隔符,默認的分隔符是空格或製表符(tab)編程

②、command:數組

BEGIN{}       {}                 END{}
行處理前      行處理         行處理後
# awk 'BEGIN{print 1/2} {print "ok"} END{print "-----------"}' /etc/hosts 0.5 ok ok ok -----------

BEGIN{}          一般用於定義一些變量,例如BEGIN{FS=":";OFS="---"}bash

③、awk命令格式app

awk 'pattern' filename                //示例:awk -F: '/root/' /etc/passwd 
awk '{action}' filename                            //示例:awk -F: '{print $1}' /etc/passwd 
awk 'pattern {action}' filename        //示例:awk -F: '/root/{print $1,$3}' /etc/passwd //示例:awk 'BEGIN{FS=":"} /root/{print $1,$3}' /etc/passwd
command |awk 'pattern {action}'              //示例:df -P| grep '/' |awk '$4 > 25000 {print $4}'
    

(三)、工做原理

# awk -F: '{print $1,$3}' /etc/passwd

①、awk 使用一行做爲輸入,並將這一行賦給這內部變量$0,每行也能夠成爲一個記錄,以換行符結束;ssh

②、而後,行被:(默認爲空格或製表符)分解成字段(或域),每一個字段存儲在一編號的變量中,從$1開始,最多達100個字段;編程語言

③、awk 如何知道用空格來分割字段的呢?由於有一個內部變量FS來肯定字段分割符。初始時,FS賦爲空格;

④、awk 打印字段時,將以設置的方法使用print函數打印,awk 在打印字段間加上空格,由於$1,$3之間有一個逗號,逗號比較特殊,它映射爲另外一個內部變量,稱爲輸出字段分割符OFS,OFS默認爲空格;

⑤、awk 輸出以後,將從文件中獲取另外一行,並將其存儲在$0中,覆蓋原來的內容,而後將新的字符將新的字符串分隔成字段並進行處理,該過成將持續到全部行處理完畢;

(四)、記錄與字段相關內部變量:man awk

$0//awk變量$0保存當前記錄的內容 # awk -F: '{print $0}' /etc/passwd
NR:        The total number of input records seen so far.       # awk -F: '{print NR, $0}' /etc/passwd /etc/hosts FNR: The input record number in the current input file        # awk -F: '{print FNR, $0}' /etc/passwd /etc/hosts NF: //保存記錄的字段數,$1,$2...$100 # awk -F: '{print $0,NF}' /etc/passwd
FS:        //輸入字段分隔符,默認空格 # awk -F: '/alice/{print $1, $3}' /etc/passwd
                                                                 # awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd # awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd OFS: //輸出字段分隔符 # awk -F: '/alice/{print $1,$2,$3,$4}' /etc/passwd
                                                                # awk 'BEGIN{FS=":"; OFS="+++"} /^root/{print $1,$2,$3,$4}' passwd RS The input record separator, by default a newline. # awk -F: 'BEGIN{RS=" "} {print $0}' a.txt ORS The output record separator, by default a newline. # awk -F: 'BEGIN{ORS=""} {print $0}' passwd

①、區別:

字段分割符:FS OFS   默認空格或製表符

記錄分割符:RS ORS  默認換行符

lab1:

[root@linux ~]# awk 'BEGIN{ORS=" "} {print $0}' /etc/passwd                 //#將文件每一行合併爲一行
ORS默認輸出一條記錄應該回車,加了一個空格

lab2:

[root@linux ~]# head -1 /etc/passwd > passwd1 [root@linux ~]# cat passwd1 root:x:0:0:root:/root:/bin/bash [root@linux ~]# [root@linux ~]# awk 'BEGIN{RS=":"} {print $0}' passwd1 root x 0
0 root /root /bin/bash [root@linux ~]# awk 'BEGIN{RS=":"} {print $0}' passwd1 |grep -v '^$' > passwd2

(五)、格式化輸出:

①、print函數

# date |awk '{print "Month: " $2 "\nYear: " $NF}' # awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd # awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd

②、printf函數

# awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}'  /etc/passwd # awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd

%s 字符類型 %d 數值類型 %f 浮點類型 佔15字符 - 表示左對齊,默認是右對齊 printf默認不會在行尾自動換行,加\n

(六)、awk 工做模式和動做

  任何awk 語句都由模式和動做組成,模式部分決定動做語句什麼時候觸發及觸發事件,處理即對數據進行的操做。

  若是省略模式部分,動做將時刻保持執行狀態,模式能夠是任何條件語句或複合語句或正則表達式,模式包括兩個特殊字段 BEGIN和END ,使用 BEGIN語句設置計數和打印頭,BEGIN 語句使用在任何文本瀏覽動做以前,以後文本瀏覽動做依據輸入文本開始執行,END 語句用來在awk 完成文本瀏覽動做後打印輸出文本總數和結尾狀態;

①、正則表達式:

匹配記錄(整行):

# awk '/^alice/'  /etc/passwd # awk '$0 ~ /^alice/'  /etc/passwd # awk '!/alice/' passwd # awk '$0 !~ /^alice/'  /etc/passwd

匹配字段:匹配操做符(~ !~)

# awk -F: '$1 ~ /^alice/'  /etc/passwd # awk -F: '$NF !~ /bash$/'  /etc/passwd

②、比較表達式:

  比較表達採用對文本進行比較,只當條件爲真,才執行指定的動做,比較表達式使用關係運算符,用於比較數字與字符串;

關係運算符

運算符 含義 示例 <               小於                            x<y <=              小於或等於                    x<=y ==              等於                            x==y !=              不等於                         x!=y >=              大於等於                       x>=y >               大於                            x>y
# awk -F: '$3 == 0' /etc/passwd # awk -F: '$3 < 10' /etc/passwd # awk -F: '$NF == "/bin/bash"' /etc/passwd # awk -F: '$1 == "alice"' /etc/passwd # awk -F: '$1 ~ /alic/ ' /etc/passwd # awk -F: '$1 !~ /alic/ ' /etc/passwd # df -P | grep  '/' |awk '$4 > 25000'

條件表達式:

# awk -F: '$3>300 {print $0}' /etc/passwd # awk -F: '{ if($3>300) print $0 }' /etc/passwd # awk -F: '{ if($3>300) {print $0} }' /etc/passwd # awk -F: '{ if($3>300) {print $3} else{print $1} }' /etc/passwd

算術運算:+ - * / %(模) ^(冪2^3)

能夠在模式中執行計算,awk 都將按浮點方式執行算術運算

# awk -F: '$3 * 10 > 500' /etc/passwd # awk -F: '{ if($3*10>500){print $0} }' /etc/passwd

邏輯操做符和複合模式:

&&        邏輯與        a&&b ||            邏輯或        a||b !            邏輯非        !a # awk -F: '$1~/root/ && $3<=15' /etc/passwd # awk -F: '$1~/root/ || $3<=15' /etc/passwd # awk -F: '!($1~/root/ || $3<=15)' /etc/passwd

範圍模式:

# awk '/Tom/,/Suzanne/' filename    

2、示例

(一)、awk 示例:

# awk '/west/' datafile # awk '/^north/' datafile # awk '$3 ~ /^north/' datafile # awk '/^(no|so)/' datafile # awk '{print $3,$2}' datafile # awk '{print $3 $2}' datafile # awk '{print $0}' datafile # awk '{print "Number of fields: "NF}' datafile # awk '/northeast/{print $3,$2}' datafile # awk '/E/' datafile # awk '/^[ns]/{print $1}' datafile # awk '$5 ~ /\.[7-9]+/' datafile # awk '$2 !~ /E/{print $1,$2}' datafile # awk '$3 ~ /^Joel/{print $3 " is a nice boy."}' datafile # awk '$8 ~ /[0-9][0-9]$/{print $8}' datafile # awk '$4 ~ /Chin$/{print "The price is $" $8 "."}' datafile # awk '/Tj/{print $0}' datafile # awk '{print $1}' /etc/passwd # awk -F: '{print $1}' /etc/passwd # awk '{print "Number of fields: "NF}' /etc/passwd # awk -F: '{print "Number of fields: "NF}' /etc/passwd # awk -F"[ :]" '{print NF}' /etc/passwd # awk -F"[ :]+" '{print NF}' /etc/passwd # awk '$7 == 5' datafile # awk '$2 == "CT" {print $1, $2}' datafile # awk '$7 != 5' datafile

(二)、awk 進階:

[root@yang ~]# cat b.txt yang sheng:is a::good boy! [root@yang ~]# awk '{print NF}' b.txt 4 [root@yang ~]# awk -F: '{print NF}' b.txt 4 [root@yang ~]# awk -F"[ :]" '{print NF}' b.txt 7 [root@yang ~]# awk -F"[ :]+" '{print NF}' b.txt 6 # awk '$7 < 5 {print $4, $7}' datafile                      #{if($7<5){print $4,$7}} # awk '$6 > .9 {print $1,$6}' datafile # awk '$8 <= 17 {print $8}' datafile # awk '$8 >= 17 {print $8}' datafile # awk '$8 > 10 && $8 < 17' datafile # awk '$2 == "NW" || $1 ~ /south/ {print $1, $2}' datafile # awk '!($8 == 13){print $8}' datafile                    #$8 != 13 # awk '/southem/{print $5 + 10}' datafile # awk '/southem/{print $8 + 10}' datafile # awk '/southem/{print $5 + 10.56}' datafile # awk '/southem/{print $8 - 10}' datafile # awk '/southem/{print $8 / 2 }' datafile # awk '/southem/{print $8 / 3 }' datafile # awk '/southem/{print $8 * 2 }' datafile # awk '/southem/{print $8 % 2 }' datafile # awk '$3 ~ /^Suan/ {print "Percentage: "$6 + .2 " Volume: " $8}' datafile # awk '/^western/,/^eastern/' datafile # awk '{print ($7 > 4 ? "high "$7 : "low "$7)}' datafile            //三目運算符 a?b:c 條件?結果1:結果2
# awk '$3 == "Chris" {$3 = "Christian"; print $0}' datafile     //賦值運算符
# awk '/Derek/ {$8+=12; print $8}' datafile                            //$8 += 12等價於$8 = $8 + 12
# awk '{$7%=3; print $7}' datafile                                        //$7 %= 3等價於$7 = $7 % 3 

3、awk 腳本編程

(一)、條件判斷

①if 語句:

格式

{if(表達式){語句;語句;...}}

awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd
awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd      //統計系統用戶數

②if...else語句:

格式

{if(表達式){語句;語句;...}else{語句;語句;...}}

awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd
awk -F: '{if($3==0) {count++} else{i++} }' /etc/passwd
awk -F: '{if($3==0){count++} else{i++}} END{print "管理員個數: "count ; print "系統用戶數: "i}' /etc/passwd

③if...else if...else語句:

格式

{if(表達式1){語句;語句;...} else if (表達式2) {語句;語句;...} else if (表達式3) {語句;語句;...} else {語句;語句;...}}

awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print i; print k; print j}' /etc/passwd
awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理員個數: "i; print "普通用個數: "k; print "系統用戶: "j}' /etc/passwd

(二)、循環

①、while:

[root@linux ~]# awk 'BEGIN{ i=1; while(i<=10){print i; i++} }' [root@linux ~]# awk -F: '/^root/{i=1; while(i<=7){print $i; i++}}' passwd [root@linux ~]# awk  '{i=1; while(i<=NF){print $i; i++}}' /etc/hosts [root@linux ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd       //將每行打印10次
[root@linux ~]# cat b.txt 111 222
333 444 555
666 777 888 999 [root@linux ~]# awk '{i=1; while(i<=NF){print $i; i++}}' b.txt                       //分別打印每行的每列
111
222
333
444
555
666
777
888
999

②、for:

[root@linux ~]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }'                              //C風格for
1
2
3
4
5 [root@linux ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd         //將每行打印10次
[root@linux ~]# awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd               //分別打印每行的每列
root x 0
0 root /root /bin/bash bin x 1
1 bin /bin /sbin/nologin

③、數組:

# awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd root # awk -F: '{username[i++]=$1} END{print username[1]}' /etc/passwd bin # awk -F: '{username[i++]=$1} END{print username[0]}' /etc/passwd root

④、數組遍歷:

1.按索引遍歷

# awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd # awk -F: '{username[++x]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd 注:變量i是索引

2.按元數個數遍歷

# awk -F: '{username[x++]=$1} END{for(i=0;i<x;i++) print i,username[i]}' /etc/passwd # awk -F: '{username[++x]=$1} END{for(i=1;i<=x;i++) print i,username[i]}' /etc/passwd

4、實例練習

(一)、統計shell

<統計/etc/passwd中各類類型shell的數量>

[root@linux ~]# awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd

(二)、網站訪問狀態統計

<當前實時狀態netstat>

[root@linux ~]# netstat -ant |grep :80 |awk '{access_stat[$NF]++} END{for(i in access_stat ){print i,access_stat[i]}}' TIME_WAIT 1064 ESTABLISHED 1 LISTEN 1 [root@linux ~]# netstat -ant |grep :80 |awk '{access_stat[$NF]++} END{for(i in access_stat ){print i,access_stat[i]}}' |sort -k2 -n |head [root@linux ~]# ss -an |grep :80 |awk '{access_stat[$2]++} END{for(i in access_stat){print i,access_stat[i]}}' LISTEN 1 ESTAB 5 TIME-WAIT 97 [root@linux ~]# ss -an |grep :80 |awk '{access_stat[$2]++} END{for(i in access_stat){print i,access_stat[i]}}' |sort -k2 -rn TIME-WAIT 18 ESTAB 8 LISTEN 1

(三)、統計當前訪問的每一個IP的數量

<當前實時狀態netstat,ss>

[root@linux ~]# netstat -ant |grep :80 |awk -F: '{ip_count[$8]++} END{for(i in ip_count){print i,ip_count[i]} }' |sort
172.16.130.16 289
172.16.130.33 254
172.16.130.44 158
172.16.130.99 4 [root@linux ~]# ss -an |grep :80 |awk -F":" '!/LISTEN/{ip_count[$(NF-1)]++} END{for(i in ip_count){print i,ip_count[i]}}' |sort -k2 -rn |head
172.16.160.77 59
172.16.160.221 16
172.16.160.17 11
172.16.160.69 8
172.16.160.51 7
172.16.160.49 7
172.16.160.13 7
172.16.160.153 3
172.16.160.79 2
172.16.160.52 2

(四)、統計Apache/Nginx日誌PV量

<統計Apache/Nginx日誌中某一天的PV量,統計日誌>

[root@linux log]# grep '22/Mar/2017' cd.mobiletrain.org.log |wc -l 1646

(五)、統計Apache/Nginx日誌

<統計Apache/Nginx日誌中某一天不一樣IP的訪問量,日誌統計>

[root@linux nginx_log]# grep '07/Aug/2012' access.log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |sort -k2 -rn |head
222.130.129.42 5761
123.126.51.94 988
123.126.68.22 588
123.114.46.141 418
61.135.249.218 368
110.75.173.162 330
110.75.173.163 327
110.75.173.161 321
110.75.173.160 319
110.75.173.164 314
[root@linux nginx_log]# grep '07/Aug/2012' access.log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |awk '$2>100' |sort -k2 -rn 222.130.129.42 5761
123.126.51.94 988
123.126.68.22 588
123.114.46.141 418
61.135.249.218 368
110.75.173.162 330
110.75.173.163 327
110.75.173.161 321
110.75.173.160 319
110.75.173.164 314
1.202.218.67 313
110.75.173.159 311
203.208.60.80 294
221.221.207.202 266
203.208.60.82 230
203.208.60.81 209
38.111.147.83 206
61.135.249.220 187
183.39.187.86 178
61.156.142.207 129
[root@linux log]# awk '/22\/Mar\/2017/{ips[$1]++} END{for(i in ips){print i,ips[i]}}' sz.mobiletrain.org.log |awk '$2>100' |sort -k2 -rn|head180.153.93.44 1327
119.147.33.19 551
119.147.33.26 234
119.147.33.22 216
119.147.33.21 214
101.69.121.35 209
183.214.128.174 193
175.6.26.173 178
27.221.28.174 167
121.29.54.11 161
[root@linux log]# awk '/22\/Mar\/2017/{ips[$1]++} END{for(i in ips){if(ips[i]>100){print i,ips[i]}}}' sz.mobiletrain.org.log|sort -k2 -rn|head
180.153.93.44 1327
119.147.33.19 551
119.147.33.26 234
119.147.33.22 216
119.147.33.21 214
101.69.121.35 209
183.214.128.174 193
175.6.26.173 178
27.221.28.174 167
121.29.54.11 161

思路:將須要統計的內容(某一個字段)做爲數組的索引++

(六)、awk 函數

統計用戶名爲4個字符的用戶:

[root@linux ~]# awk -F: '$1~/^....$/{count++; print $1} END{print "count is: " count}' /etc/passwd root sync halt mail news uucp nscd vcsa pcap sshd dbus jack count is: 12
[root@linux ~]#  awk -F: 'length($1)==4{count++; print $1} END{print "count is: "count}' /etc/passwd root sync halt mail news uucp nscd vcsa pcap sshd dbus jack count is: 12

(七)、awk 使用外部變量:

①方法一:在雙引號的狀況下使用

[root@linux ~]# var="bash" [root@linux ~]# echo "unix script" |awk "gsub(/unix/,\"$var\")" bash script

②方法二:在單引號的狀況下使用

[root@linux ~]# var="bash" [root@linux ~]# echo "unix script" |awk 'gsub(/unix/,"'"$var"'")' bash script

 

[root@linux ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/cl-root  2.8T  246G  2.5T   9% / tmpfs 24G 20K 24G 1% /dev/shm /dev/sda2           1014M  194M  821M   20% /boot

 

[root@linux ~]# df -h |awk '{ if(int($5)>5){print $6":"$5} }'
/:9%
/boot:20%

 

[root@linux ~]# i=10 [root@linux ~]# df -h |awk '{ if(int($5)>'''$i'''){print $6":"$5} }'
/boot:20%

方法:awk 參數-v(建議)

[root@linux ~]# echo "unix script" |awk -v var="bash" 'gsub(/unix/,var)' bash script [root@linux ~]# awk -v user=root  -F: '$1 == user' /etc/passwd root:x:0:0:root:/root:/bin/bash

經常使用方法:

head 默認爲前十;

cat a.txt | awk 'BEGIN{FS="/"}{dict[$3]++}END{for (i in dict)print dict[i],i}' | sort -r | head -20
相關文章
相關標籤/搜索