天天看點

AWK

目錄

  • 一、AWK概述
  • 二、行與列
    • 行操作
    • 列操作
  • 三、取磁盤的使用率--案例
  • 四、正規表達式
  • 五、範圍做為條件
  • 六、BEGIN和END

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

張賀,多年網際網路行業工作經驗,擔任過網絡工程師、系統內建工程師、LINUX系統運維工程師

個人網站:www.zhanghehe.cn

AWK

的内容也太多了,簡單的做一個複習,都差點閃了老腰!

AWK

我了解的

awk

的作用就是取列和取列并計算,當我們一想到取列或者取列計算的時候就應當立馬想到

awk

,另外,

awk

還相當不要臉的包攬了它二弟和它三弟的部分工作,讓我很是焦灼,在使用的時候不知道用哪個好!

AWK

AWK

的使用者與

sed

的用法相似,它的文法是這樣的:

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

awk

的選項其實比較少,常用就是

-F

,用來指定分隔符,最有亮點的地方是分隔符竟然可以指定多個!!!

AWK
//大于号可以換成大于、大于等于、小于、小于等于,等于
[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
           

  

AWK

使用awk的注意點:

  1. 一定要用單引号,三劍客最好都要使用單引号,不然會出各種奇怪的事情!
  2. 分隔符可以指定多個,如果不指定的的話,預設就是以空格或連續的空格,TAB或 者連續的TAB為分隔符的。
  3. awk的選項使用的不多,最常用的選項就是指定分隔符,即-F的選項,偶爾會用 到-v OFS,不過很少。
  4. “幹啥”的選項也比較少,最常用的也就是p,即print列印,預設就是print打 印。
  5. awk本來就支援擴充的正規表達式,無需像sed一樣加r

NR

number 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/passwd

less -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}是可以省略的。
           

案例一:顯示磁盤使用率大于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
           

做為條件我們上面在描述條件的時候都是用的行号,其實我們還可以使用正規表達式做為條件。 比如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
           

比如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
           

注意:^在

grep

sed

當中隻能表示以什麼什麼開頭的行,在

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
           

記住:

  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原名文本報名生成器,用來生成報告用的,生成報告的話一定會用 到統計了。

1 [root@centos7 tmp]# awk '/^$/{i++;print i}' /tmp/test.sh #有5個空行,這不是我想要的結果
2 1
3 2
4 3
5 4
6 5
           
1 [root@centos7 tmp]# awk '/^$/{i++}END{print i}' /tmp/test.sh #完成之後再打開出變量i,這裡的變量i已經增長到5了,這時候列印出來正合适呢!
2 5
           
和: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