AWK

 

 


+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
張賀,多年互聯網行業工做經驗,擔任過網絡工程師、系統集成工程師、LINUX系統運維工程師
我的網站:www.zhanghehe.cn
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-linux


1、AWK概述

AWK的內容也太多了,簡單的作一個複習,都差點閃了老腰!nginx

img

我理解的awk的做用就是取列和取列並計算,當咱們一想到取列或者取列計算的時候就應當立馬想到 awk,另外,awk還至關不要臉的包攬了它二弟和它三弟的部分工做,讓我非常焦灼,在使用的時候不知道用哪一個好!正則表達式

img

AWK的用戶與sed的用法類似,它的語法是這樣的:centos

awk <選項> '找誰{幹啥}' #必定要注意引號是英文的單引號

awk的選項其實比較少,經常使用就是-F,用來指定分隔符,最有亮點的地方是分隔符居然能夠指定多個!!!bash

img

//大於號能夠換成大於、大於等於、小於、小於等於,等於
[root@centos7 ~]# awk 'NR>=2{print}' /etc/passwd 

// 打印出第三行的第二列
//awk默認以一個或連續多個空格,TAB,連續多個TAB爲分隔符,因此這裏面不指定分隔符,默認就是以空格爲分隔符的。
ip a s ens33 | awk 'NR==3{print $2}'
192.168.80.200/24
ifconfig eth0 | awk 'NR==2{print $2}'
192.168.80.2

//指定使用空格和斜線爲分隔符,指定多個分隔符,並指定了次數,一次或屢次,也就說使用了[]以後,連續之意失效了,須要手動經過擴展的正則表達式加號強調。
[root@centos7 ~]# ip a s ens33 | awk ‐F'[ /]+' 'NR==3{print $3}'
192.168.80.200

  img

使用awk的注意點:網絡

  1. 必定要用單引號,三劍客最好都要使用單引號,否則會出各類奇怪的事情!app

  2. 分隔符能夠指定多個,若是不指定的的話,默認就是以空格或連續的空格,TAB或 者連續的TAB爲分隔符的。less

  3. awk的選項使用的很少,最經常使用的選項就是指定分隔符,即-F的選項,偶爾會用 到-v OFS,不過不多。運維

  4. 「幹啥」的選項也比較少,最經常使用的也就是p,即print打印,默認就是print打 印。ide

  5. awk原本就支持擴展的正則表達式,無需像sed同樣加r

2、行與列

行操做

NRnumber is recored的縮寫,其實就是行號的意思,如上面 的例子所示。

$0表明的是一整行,$1表明的就不是第一行了,$1表明的就是第一列,其實咱們把$0理解成全部列就很天然了,END表明的最後一列,咱們下面有例子。

//若是不指定是第一行NR==1,它默認就會把文件裏面的第一列所有給你打印出來
[root@centos7 ~]# awk ‐F':' 'NR==1{print $0}' /etc/passwd 
root:x:0:0:root:/root:/bin/bash

//END表明最後一行,打印最後一行,{print $0}是默認的,即便不寫,效果也是同樣的。
[root@centos7 ~]# awk 'END{print $0}' /etc/passwd 
zhanghe:x:1000:1000:zhanghe:/home/zhanghe:/bin/bash

//你看,不加'$0',效果是同樣的,END(print $0) 至關於 END (print)
[root@centos7 ~]# awk 'END{print}' /etc/passwd 
zhanghe:x:1000:1000:zhanghe:/home/zhanghe:/bin/bash #sed ‐n '$p sed也能夠實現這樣的效果

那若是我想要第2行之後的行呢?就正常寫就行,以下

1 [root@centos7 ~]# awk 'NR>=2{print}' /etc/passwd

行號也能夠單獨的使用,好比我想顯示出/etc/passwd的行號,也就說想要實現cat -n /etc/passwdless -N /etc/passwd的功能

[root@centos7 ~]# awk '{print NR}' /etc/passwd #這樣僅把全部的行號打印出來了
1
2
3
4
……
//在行號後面再加一個$0,$0啥意思還記得嗎?表明全部列,行號加上顯示全部列就會有cat ‐n的效果了。
[root@centos7 ~]# awk '{print NR,$0}' /etc/passwd 
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin

其實,sed能作取行操做,awk也能作,好比:

1 [root@centos7 ~]# sed ‐n 2p /etc/passwd #打印第二行
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 [root@centos7 ~]# awk 'NR==2{print}' /etc/passwd #打印第二行
4 bin:x:1:1:bin:/bin:/sbin/nologin

列操做

上述例子當中的「$數字」的意思其實就是取哪一列,‘print $3’其實就是取第3列,若是 咱們想取多列呢?好比我想取出/etc/passwd文件文件當中第1列和第3列,怎麼搞呢?

//取最後一行的第一列和最後三列
[root@centos7 ~]# awk ‐F':' 'END{print $1,$3}' /etc/passwd 
zhanghe 1000

那若是咱們想取最後一列呢?咱們知道END表明最後一行,最後一列用NF來表示,以下所 示:

1 [root@centos7 ~]#awk -F':' 'END{print $NF}' /etc/passwd
2 /bin/bash

取最後一列,會用到什麼地方呢?好比,日誌文件,/var/log/secure文件下的日誌的長度並非固定的,在取日誌記錄的最後一部分的時候,咱們能夠用到取最後一列。 那取倒數第二列呢?

1 [root@centos7 ~]# awk ‐F':' 'NR==1{print $NF‐1}' /etc/passwd #這樣寫不行,須要加上一個括號,以下所示:
2 ‐1
3 [root@centos7 ~]# awk ‐F':' 'NR==1{print $(NF‐1)}' /etc/passwd
4 /root
5 [root@centos7 ~]# echo 66 77 88 | awk '{print $NF‐1}'
6 87
7 [root@centos7 ~]# echo 66 77 88 | awk '{print $(NF‐1)}'
8 77

其實取列的時候還能夠進行比較呢?好比 ,我想要找到/etc/passwd當中第三列大於500的 行。

1 [root@centos7 ~]# awk ‐F':' '$3>500{print $0}' /etc/passwd #後面的{print$0}是能夠省略的。
3、取磁盤的使用率--案例

案例一:顯示磁盤使用率大於10%的分區和掛載點

[root@centos7 ~]# df ‐h | awk '$5>10%' #列比較的時候不能識別%號
awk: cmd. line:2: $5>10%
awk: cmd. line:2: ^ unexpected newline or end of string
[root@centos7 ~]# df ‐h | awk '$5>10' #不加%,會不許,你看,下面把8%的也顯示
出來了,下面有解釋
文件系統 容量 已用 可用 已用% 掛載點
/dev/mapper/centos_centos7‐root 50G 3.9G 47G 8% /
/dev/sda1 1014M 179M 836M 18% /boot
[root@centos7 ~]# df ‐h | sed 's@%@@g' | awk '$5>10{print $1,$NF}' #經過sed把%全都刪除
文件系統 掛載點
/dev/sda1 /boot
[root@centos7 ~]# df ‐h | sed 's@%@@g' | awk '$5>10{print $1,$NF}' | tai
l ‐1 #這樣的結果就正常了。
/dev/sda1 /boot

爲何會出現不許的狀況?其實並非不許,LINUX系統不會騙咱們的,只不過,它默認不是按照咱們覺得的方式在比大小,以下所示:

[root@centos7 ~]# seq 10 #生成10個數
1
2
3
4
5
6
7
8
9
10
[root@centos7 ~]# seq 10 | sort #使用sort對它們進行排序,結果2比10大?這是怎麼回事?是由於linux在比較大小的時候默認是按位進行比較的,
13 1
14 10
15 2
16 3
17 4
18 5
19 6
20 7
21 8
22 9
23 [root@centos7 ~]# seq 10 | sort ‐n #加一個‐n的參數,就是按照數字的大小進行排序,你看,這又恢復正常了。
24 1
25 2
26 3
27 4
28 5
29 6
30 7
31 8
32 9
33 10

若是問題再難一點,顯示出磁盤使用率大於10%且小於50%的磁盤分區和掛載點呢?就用 &&符號就行,&&就是而且的意思嘛!以下所示:

1 [root@centos7 ~]# df ‐h | sed 's@%@@g' | awk '$5>10&&$5<50{print $1,$NF}'
| tail ‐1
2 /dev/sda1 /boot

咱們在看行的時候也可使用,咱們咱們想看第三行到第六行中間的行:

1 [root@centos7 ~]# awk 'NR>3&&NR<6{print NR,$0}' /etc/passwd
2 4 adm:x:3:4:adm:/var/adm:/sbin/nologin
3 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
1 [root@centos7 ~]# sed ‐n '4,5p' /etc/passwd
2 adm:x:3:4:adm:/var/adm:/sbin/nologin
3 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
4、正則表達式

作爲條件咱們上面在描述條件的時候都是用的行號,其實咱們還可使用正則表達式作爲條件。 好比1:過濾出包含數字的行

1 [root@centos7 test.dir]# cat test.txt
2 zhanghe
3 zhanghe6
4 [root@centos7 test.dir]# awk '/[0‐9]/' test.txt #awk在使用正則表達式作爲條件的時候要用//號的,sed也是這樣,完整的寫法是這樣的'/[0‐9]/{print $0}'
5 zhanghe6
6 [root@centos7 test.dir]# grep '[0‐9]' test.txt
7 zhanghe6

好比2:過濾出/etc/passwd當中開頭是root一直到結尾是shutdown之間的行

[root@nginx ~]# sed -n '/^root/,/shutdown$/p' /etc/passwd
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
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

[root@nginx ~]# awk '/^root/,/shutdown$/' /etc/passwd
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
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

好比3:過濾出/etc/passwd當中開關是root一直到結尾是shutdown之間的行的最後一列

[root@nginx ~]# awk -F: '/^root/,/shutdown$/ {print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
/sbin/shutdown

好比4:顯示出最後一列是bash的用戶名,下面這個最是騷氣,直接指定去匹配哪個列 

1 [root@centos7 ~]# awk ‐F':' '$NF~/bash$/{print $1}' /etc/passwd
2 root
3 zhanghe
5、範圍作爲條件

好比1:顯示以一個z或者一個r開頭的用戶名

1 [root@centos7 ~]# awk ‐F':' '$1~/^(r|z)/{print $1}' /etc/passwd #也能夠這樣寫:awk ‐F':' '$1~/^[rz]/{print $1}'
2 root
3 rpc
4 rtkit
5 radvd
6 rpcuser
7 zhanghe

注意:^在grepsed當中只能表示以什麼什麼開頭的行,在awk當中能夠經過前而的列表示某一列當中以什麼開頭的行,也就是說範圍增長了。 好比2:顯示UID號碼最爲一位是1或是5的全名

1 [root@centos7 ~]# awk ‐F':' '$3~/[15]$/{print $1}' /etc/passwd
2 bin
3 sync
4 operator
5 dbus
6 pulse
7 radvd
8 unbound
9 setroubleshoot
1 [root@centos7 ~]# awk ‐F':' '{print $3,$4}' /etc/passwd | head ‐4
2 0 0
3 1 1
4 2 2
5 3 4
6 [root@centos7 ~]# awk ‐F':' '{print "#"$3"#"$4}' /etc/passwd | head ‐4 #能夠在裏面加點東西,要用雙引號才能夠,雙引號裏面有什麼,就會原封不動的顯示什麼。
7 #0#0
8 #1#1
9 #2#2
10 #3#4

用awk作sed的替換功能 用gsub函數,用法:{gsub (/????,"$")} 將雙豎線的內容替換爲雙引號裏面的內容

1 [root@centos7 ~]# awk '{gsub (/:/,"$");print}' /etc/passwd | head ‐4
2 root$x$0$0$root$/root$/bin/bash
3 bin$x$1$1$bin$/bin$/sbin/nologin
4 daemon$x$2$2$daemon$/sbin$/sbin/nologin
5 adm$x$3$4$adm$/var/adm$/sbin/nologin
1 [root@centos7 ~]# awk '{gsub (/r/,"R") $1;print}' /etc/passwd | head ‐4 #精確替換哪一列的什麼
2 Root:x:0:0:Root:/Root:/bin/bash
3 bin:x:1:1:bin:/bin:/sbin/nologin
4 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 adm:x:3:4:adm:/vaR/adm:/sbin/nologin
6 [root@centos7 ~]# awk '{gsub (/:/,"$");print}' /etc/passwd | head ‐4 #不指定哪一列就是一整行,至關於$0,也就是全部列
7 root$x$0$0$root$/root$/bin/bash
8 bin$x$1$1$bin$/bin$/sbin/nologin
9 daemon$x$2$2$daemon$/sbin$/sbin/nologin
10 adm$x$3$4$adm$/var/adm$/sbin/nologin

顯示人名和UID,而後以逗號分隔,就用最簡單的方式便可

1 [root@centos7 ~]# awk ‐F':' '{print $1,$3}' /etc/passwd | head ‐4
2 root 0
3 bin 1
4 daemon 2
5 adm 3
6 [root@centos7 ~]# awk ‐F':' '{print $1","$3}' /etc/passwd | head ‐4
7 root,0
8 bin,1
9 daemon,2
10 adm,3
6、BEGIN和END

記住:

  1. BEGIN裏面的內容會在awk讀取文件以前執行,通常來用計算。

  2. END裏面的內容會有awk讀取文件以後執行,通常用來作統計。

BEGIN:

1 [root@centos7 ~]# awk 'BEGIN{print 1+2,1‐8}'
2 3 ‐7
3 [root@centos7 ~]# awk ‐F':' 'BEGIN{OFS="$$$"}{print $1,$2}' /etc/passwd |
head ‐4 #也能夠用來修改變量,至關於上面講的‐v OFS
4 root$$$x
5 bin$$$x
6 daemon$$$x
7 adm$$$x

END: 何時用END?統計的時候,先進行計算,最後END()顯示最後結果,其實這纔是 awk最重要的功能,awk原名文本報名生成器,用來生成報告用的,生成報告的話必定會用 到統計了。

統計/etc//services 文件當中空行的數量 i=i+1 至關於i++ 用來出現的總次數,初始值是0. 

1 [root@centos7 tmp]# awk '/^$/{i++;print i}' /tmp/test.sh #有5個空行,這不是我想要的結果
2 1
3 2
4 3
5 4
6 5

img

1 [root@centos7 tmp]# awk '/^$/{i++}END{print i}' /tmp/test.sh #完成以後再打開出變量i,這裏的變量i已經增加到5了,這時候打印出來正合適呢!
2 5

求和:i=i+$,至關於i+=$

和:i=i+$,至關於i+=$
1 [root@centos7 tmp]# cat test.txt
2 12
3 11
4 14
5 [root@centos7 tmp]# awk '{sum += $1};END{print sum}' test.txt #對第一列進行求和
6 37
1 [root@centos7 tmp]# cat test.txt
2 12 45
3 11 11
4 14 13
5 [root@centos7 tmp]# awk '{sum += $2};END{print sum}' test.txt #對第二列進行求和
6 69
1 [root@centos7 tmp]# cat test.txt
2 aaa 12 45
3 aaa 11 11
4 aaa 14 13
5 bbb 1 2
6 [root@centos7 tmp]# awk '/aaa/{sum += $3}END{print sum}' test.txt #對符號條件的行進行求和
7 69
//補充
ifconfig eth0 | sed 's@^[[:space:]]\+@@g' | awk '/^inet/{ print $2}' | head -1
192.168.80.9
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息