AWK常用技巧


1.1 介紹

awk其名稱得自於它的創始人 Alfred Aho Peter Weinberger Brian Kernighan 姓氏的首個字母。實際上 AWK 的確擁有自己的語言: AWK 程序設計語言 三位創建者已將它正式定義為“樣式掃描和處理語言”。

它允許您創建簡短的程序,這些程序讀取輸入文件、為數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。

awk 是一種很棒的語言,它適合文本處理和報表生成,其語法較為常見,借鑒了某些語言的一些精華,如 C 語言等。在 linux 系統日常處理工作中,發揮很重要的作用,掌握了 awk將會使你的工作變的高大上。

1.1.1 AWK原理

這需要一個例子來說明,你將會見到/etc/passwd 文件的內容出現在眼前。

awk '{print $0}' /etc/passwd
echo clsn|awk '{print "hello,world"}'
awk '{ print "clsn" }' /etc/passwd

現在,解釋 awk 做了些什么。調用 awk時,我們指定/etc/passwd 作為輸入文件。執行 awk 時,它依次對/etc/passwd 中的每一行執行 print 命令。所有輸出都發送到 stdout,所得到的結果與執行 cat /etc/passwd 完全相同。現在,解釋{ print }代碼塊。在 awk 中,花括號用於將幾塊代碼組合到一起,這一點類

似於C 語言。在代碼塊中只有一條 print 命令。在awk 中,如果只出現 print 命令,那么將打印當前行的全部內容。

再次說明,awk 對輸入文件中的每一行都執行這個腳本。

 

1.2 AWK常用速查表

1.2.1 AWK運算符

運算符

說明

賦值運算符

= += -= *= /= %= ^= **=

賦值語句

邏輯運算符

||

邏輯或

&&

邏輯與

正則運算符

~ !~

匹配正則表達式和不匹配正則表達式

關系運算符

< <= > >= != ==

關系運算符

算術運算符

+ -

加,減

* / &

乘,除與求余

+ - !

一元加,減和邏輯非

^ ***

求冪

++ --

增加或減少,作為前綴或后綴

其他運算符

$

字段引用

空格

字符串鏈接符

?:

三目運算符

In

數組中是否存在某鍵值

1.2.2 常用AWK內置變量

變量名

$0

當前記錄

$1~$n

當前記錄的第 n 個字段

FS

輸入字段分隔符 默認是空格

RS

輸入記錄分割符 默認為換行符

NF

當前記錄中的字段個數,就是有多少列

NR

已經讀出的記錄數,就是行號,從 1 開始

OFS

輸出字段分隔符 默認也是空格

ORS

輸出的記錄分隔符 默認為換行符

1.2.3 awk中的正則

元字符

功能

示例

解釋

^

行首定位符

/^root/

匹配所有以 root 開頭的行

$

行尾定位符

/root$/

匹配所有以 root 結尾的行

.

匹配任意單個字符

/r..t/

匹配字母 r,然后兩個任意字符,再以 l

結尾的行,比如 root,r33l

*

匹配 0 個或多個前導字符(包括回車)

/a*ool/

匹配 0 個或多個 a 之后緊跟着 ool 的行,比如 oolaaaaool

+

匹配 1 個或多個前導字符

/a+b/

匹配 1 個或多個 a b 的行,比如

ab,aab

?

匹配 0 個或 1 個前導字符

/a?b/

匹配 b ab 的行

[]

匹配指定字符組內的任意一個字符

/^[abc]

匹配以字母 a b c 開頭的行

[^]

匹配不在指定字符組內任意一個字符

/^[^abc]/

匹配不以字母 a b c 開頭的行

()

子表達式組合

/(rool)+/

表示一個或多個 rool 組合,當有一些字符需要組合時,使用括號括起來

|

或者的意思

/(root)|B/

匹配root 或者 B 的行

\

轉義字符

/a\/\//

匹配 a//

~,!~

匹配,不匹配的條件語句

$1~/root/

匹配第一個字段包含字符root 的所有記錄

x{m}

x 重復m

/(root){3}/

需要注意一點的是,root 加括號和不

x{m,}

x 重復至少m

/(root){3,}/

加括號的區別,x 可以表示字符串也

X{m,n}

x 重復至少 m 次,

但不超過 n

/(root){5,6}/

可以只是一個字符,所以/root\{5\}/

表示匹配roo 再加上5 t,及roottttt

 

需要指定參數:

-posix         或者

--re-interval     有該參數不能使用該模式

cat   rex.txt smierth,harry smierth,reru robin,tom

/\(root\)\{2,\}/   

rootrootrootroot

awk -posix '/er\{1,2\}/' rex.text smierth,harry

smierth,reru

1.2.4 awk 常用函數表

函數

說明

gsub( Ere, Repl, [ In ] )

除了正則表達式所有具體值被替代這點,它和 sub 函數完全一樣地執行,。

sub( Ere, Repl, [ In ] )

Repl 參數指定的字符串替換 In 參數指定的字符串中的由 Ere參數指定的擴展正則表達式的第一個具體值。sub 函數返回替換的數量。出現在 Repl 參數指定的字符串中的 &(和符號)由 In 參數指定的與 Ere 參數的指定的擴展正則表達式匹配的字符串替換。如果未指定 In 參數,缺省值是整個記錄($0 記錄變量)。

index( String1, String2 )

在由 String1 參數指定的字符串(其中有出現 String2 指定的參數)中,返回位置,從 1 開始編號。如果 String2 參數不在 String1  參數中出現,則返回 0(零)。

length [(String)]

返回 String  參數指定的字符串的長度(字符形式)。如果未給出

String  參數,則返回整個記錄的長度($0  記錄變量)。

blength [(String)]

返回 String  參數指定的字符串的長度(以字節為單位)。如果未給出

String  參數,則返回整個記錄的長度($0  記錄變量)。

substr( String, M, [ N ] )

返回具有 N 參數指定的字符數量子串。子串從 String 參數指定的字符串取得,其字符以 M 參數指定的位置開始。M 參數指定為將

String 參數中的第一個字符作為編號 1。如果未指定 N 參數,則子串的長度將是 M 參數指定的位置到 String 參數的末尾 的長度。

match( String, Ere )

String  參數指定的字符串(Ere  參數指定的擴展正則表達式出現在其中)中返回位置(字符形式),從 1  開始編號,或如果 Ere  參數不出現,則返回 0(零)。RSTART  特殊變量設置為返回值。RLENGTH特殊變量設置為匹配的字符串的長度,或如果未找到任何匹配,則設置為 -1(負一)。

split( String, A, [Ere] )

String 參數指定的參數分割為數組元素 A[1], A[2], . . ., A[n],並返回變量的值。此分隔可以通過 Ere  參數指定的擴展正則表達式進行,或用當前字段分隔符(FS 特殊變量)來進行(如果沒有給出 Ere參數)。除非上下文指明特定的元素還應具有一個數字值,否則 A  

1.3 AWK實踐

1.3.1 函數的簡單使用

[root@clsn6 ~]# awk '{gsub(/[0-9]+/,"");print}' /tmp/passwd 
root:x:::root:/root:/bin/bash
bin:x:::bin:/bin:/sbin/nologin
daemon:x:::daemon:/sbin:/sbin/nologin
adm:x:::adm:/var/adm:/sbin/nologin
lp:x:::lp:/var/spool/lpd:/sbin/nologin
sync:x:::sync:/sbin:/bin/sync
···

1.3.2 統計系統中的secure文件中誰在破解你的密碼

1、找到誰在破解密碼

[root@clsn6 awk]# awk '/Failed/{print $(NF-3)}' secure-20161219 |sort |uniq -c  |sort -nk1
      1 103.237.144.68
      1 122.228.238.66
      1 195.20.3.210
      1 85.93.5.71
···

2、過濾出包含Failed password的行 並統計每個ip地址出現的次數

[root@clsn6 awk]# awk '/Failed/{fa[$(NF-3)]++}END{for(pol in fa)print pol,fa[pol]}' secure-20161219 |sort -rnk2
218.65.30.25 68652
218.65.30.53 34326
218.87.109.154 21201
112.85.42.103 18065
112.85.42.99 17164
218.87.109.151 17163

1.3.3 統計secure文件中每個用戶,被同一ip破解多少次

1、進破解使用的用戶及地址定向到文件中

[root@clsn6 awk]# awk '/Failed/{print $(NF-5),$(NF-3)}' secure-20161219 >user-ip.log

2、對文件進行去重排序測

[root@clsn6 awk]# awk '{h[$1" "$2]++}END{for(p in h) print p,h[p]}' user-ip.log |head 
export 209.126.122.70 3
cvsadmin 209.126.122.70 3
user1 209.126.122.70 1
dasusr1 209.126.122.70 4
1 118.100.251.170 1
git 209.126.122.70 5
boss 195.154.50.61 1
user1 46.139.219.84 2
www 123.31.34.165 2
webmaster 195.154.50.61 1

3、操作日志文件,取出數據

[root@clsn6 awk]# awk '/Failed/{h[$(NF-5)" "$(NF-3)]++}END{for(p in h) print p,h[p]}'  secure-20161219 |head
export 209.126.122.70 3
cvsadmin 209.126.122.70 3
user1 209.126.122.70 1
dasusr1 209.126.122.70 4
1 118.100.251.170 1

1.3.4 統計nginx access.log文件中對ip地址去重並統計重復數

[root@clsn6 awk]# awk '{h[$1]++}END{for(i in h) print i,h[i]}' access.log |sort -nrk2 |head 
58.220.223.62 12049
112.64.171.98 10856
114.83.184.139 1982

1.3.5 統計access.log文件中每個ip地址使用了多少流量

1、流量總計

[root@clsn6 awk]# awk '{sum=sum+$10}END{print sum}' access.log 
2478496663
[root@clsn6 awk]# awk '{sum=sum+$10}END{print sum/1024^3}' access.log 
2.30828

2、每個ip使用的流量

[root@clsn6 awk]# awk '{h[$1]=h[$1]+$10}END{for(p in h) print p,h[p]/1024^2 }' access.log |sort -rnk2|column -t |head 
114.83.184.139   29.91
117.136.66.10    21.3922
116.216.30.47    20.4716
223.104.5.197    20.4705
116.216.0.60     18.2584

1.3.6 統計access.log文件中每個ip地址使用了多少流量和每個ip地址的出現次數

[root@clsn6 awk]# awk '{count[$1]++;sum[$1]=sum[$1]+$10}END{for(pol in sum)print pol,count[pol],sum[pol]}' access.log |sort -nrk2 |column -t |head 
58.220.223.62    12049  12603075
112.64.171.98    10856  15255013
114.83.184.139   1982   31362956
117.136.66.10    1662   22431302
115.29.245.13    1318   1161468
223.104.5.197    961    21464856
116.216.0.60     957    19145329

格式化命令

awk '{
  count[$1]++
  sum[$1]+=$10
}END{
  for(pol in sum)
  print pol,count[pol],sum[pol]
}' access.log |sort -nrk3 |head

格式化后執行

[root@clsn6 awk]# awk '{
  count[$1]++
  sum[$1]+=$10
}END{
  for(pol in sum)
  print pol,count[pol],sum[pol]
}' access.log |column -t|  sort -nrk3 |head 
114.83.184.139   1982   31362956
117.136.66.10    1662   22431302
116.216.30.47    506    21466000
223.104.5.197    961    21464856
116.216.0.60     957    19145329
114.141.164.180  695    17219553
114.111.166.22   753    17121524
223.104.5.202    871    16911512
116.228.21.187   596    15969887
112.64.171.98    10856  15255013

1.3.7 按要求得到最后面的格式的結果

文件內容

cat >next2.txg<< EOF
web01[192.168.2.100]
httpd            ok
tomcat            ok
sendmail          ok
web02[192.168.2.101]
httpd            ok
postfix           ok
web03[192.168.2.102]
mysqld           ok
httpd            ok
EOF

想要的結果:

web01[192.168.2.100] httpd            ok
web01[192.168.2.100] tomcat           ok
web01[192.168.2.100] sendmail          ok
web02[192.168.2.101] httpd            ok
web02[192.168.2.101] postfix           ok
web03[192.168.2.102] mysqld           ok
web03[192.168.2.102] httpd            ok

方法一:

[root@clsn6 awk]# awk '/^web/{tmp=$0} !/^web/{print tmp,$0}' next.txt 
web01[192.168.2.100] httpd            ok
web01[192.168.2.100] tomcat           ok
web01[192.168.2.100] sendmail         ok
web02[192.168.2.101] httpd            ok
web02[192.168.2.101] postfix          ok
web03[192.168.2.102] mysqld           ok
web03[192.168.2.102] httpd            ok

方法二:

[root@clsn6 awk]# awk '/^web/{tmp=$0;next}{print tmp,$0}' next.txt 
web01[192.168.2.100] httpd            ok
web01[192.168.2.100] tomcat           ok
web01[192.168.2.100] sendmail         ok
web02[192.168.2.101] httpd            ok
web02[192.168.2.101] postfix          ok
web03[192.168.2.102] mysqld           ok
web03[192.168.2.102] httpd            ok

next:停止處理當前行,從頭開始處理下一行

[root@clsn6 awk]# seq 5 |awk 'NR==3{next}{print NR,$0}'
1 1
2 2
4 4
5 5
[root@clsn6 awk]# seq 5 |awk 'NR==1{next}{print NR,$0}'
2 2
3 3
4 4
5 5

跳過偶數行

[root@clsn6 awk]# seq 5 |awk 'NR%2==0{next}{print NR,$0}'
1 1
3 3
5 5

跳過奇數行

[root@clsn6 awk]# seq 5 |awk 'NR%2==1{next}{print NR,$0}'
2 2
4 4

1.3.8 統計每個學生的總成績和平均成績

成績文件

cat > chengji.txt <<EOF
cc 90 98 98 96 96 92
ll 70 77 85 83 70 89
ss 85 92 78 94 88 91
nn 89 90 85 94 90 95
bb 84 88 80 92 84 82
gg 64 80 60 60 61 62
EOF

算出總和

[root@clsn6 awk]#  awk '{sum=0;for(i=2;i<=NF;i++)sum+=$i;print $1,sum}' chengji.txt 
cc 570
ll 474
ss 528
nn 543
bb 510
gg 387

算出平均數

[root@clsn6 awk]#  awk '{sum=0;for(i=2;i<=NF;i++)sum+=$i;avg=sum/(NF-1);print $1,sum,avg}' chengji.txt 
cc 570 95
ll 474 79
ss 528 88
nn 543 90.5
bb 510 85
gg 387 64.5

格式化命令

awk '{
    sum=0
    for(i=2;i<=NF;i++)
    sum+=$i
    avg=sum/(NF-1)
    print $1,sum,avg
}' chengji.txt

1.3.9 打印下面語句中字符數小於6的單詞

文件內容

echo "I am clsn ops,I very like linux hahahaha." > text.txt

shell方法

[root@clsn6 awk]# for i in `sed  's#,# #g' text.txt`
> do 
>    [ ${#i} -lt 6 ] && echo $i
> done
I
am
clsn
ops
I
very
like
linux

grep 方法

[root@clsn6 awk]# egrep -wo '[a-Z]{,6}' text.txt 
I
am
clsn
ops
I
very
like
linux

awk方法

[root@clsn6 awk]# echo clsn |awk '{print length($1)}'
4
[root@clsn6 awk]# awk -F "[, ]" '{for(i=1;i<=NF;i++) if (length($i)<6) print $i}'   text.txt 
I
am
clsn
ops
I
very
like
linux

1.4 附錄

1.4.1 sort命令的使用

[root@clsn6 awk]# du -sh /* 2>/dev/null|sort -hr
1.1G    /usr
214M    /lib
120M    /var
109M    /root
38M    /boot
···

1.4.2 統計流量使用的命令

[root@clsn6 ~]# yum install htop iotop iftop atop nethogs -y
# iftop 總體流量使用情況
# nethogs 顯示進行級別的流量使用

1.4.3 其他日志分析方法

awstat,piwiki,elk

1.5 參考文獻

[1] https://www.gnu.org/software/gawk/manual/gawk.html

[2] https://www.cnblogs.com/ginvip/p/6352157.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM