1. 程式人生 > >awk用法詳解

awk用法詳解

awk

一、awk介紹

??awk是文本三劍客之一,其實awk是一種語言,該語言的創始者定義為”生成報表和格式化文本輸出“awk有很多種版本,這裏介紹的是GUN awk(gawk)

二、awk工作原理

??第一步:執行BEGIN{action}語句塊中的語句,該語句塊不依賴於文件,awk在執行是,將在讀取文件之前執行該語句中的語句塊,常用語變量的初始化,打印輸出表格的表頭。
??第二步:從文件、標準輸入、上一條命令輸出結果輸入地區一行,然後進行pattern{aciton}語句塊,它將逐行掃描文件,從第一行到最後一行。若沒有提供pattern語句,則默認執行打印{print},即打印每一個讀取到的行。
??第三步:當讀至文件最後時,執行END{action}語句塊。通常用於匯總在pattern語句中執行的過程

三、awk基本用法

選項
-F"指定分隔符"
-v 自定義變量:定義變量
? ? ??
awk {print} file
awk將把file文件中的每一行都讀取一遍,然後輸出在終端上
輸入內置變量在文本中代表如下圖所示
技術分享圖片

[root@centos6 ~]#awk -F: -v OFS="===" -v  ORS="####" ‘{print $1,$2}‘ /etc/passwd  #將輸出間隔符換為===將換行符換為###輸出結果如下
root===x####bin===x####daemon===x####adm===x####lp===x####sync===x####shutdown===x####halt===x####mail===x####uucp===x####operator===x####games===x####gopher===x####ftp===x####nobody===x####vcsa===x####saslauth===x####postfix===x####sshd===x####lin===x####tcpdump===x####hacker===x####dbus===x####test===x####apache===x####[root@centos6 ~]# ?

技術分享圖片
實例一

[root@centos6 ~]#awk -F: ‘{print $1,$3}‘ /etc/passwd #表示已“ : ”為分隔符,取第一列和第三列,然後將結果輸出出來
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
uucp 10
operator 11

四、awk內置變量

??awk命令的print打印內容也可以不與文件有關,若沒有關系,則表示文件有多少行內容,就會打印自己所指定的內容,而在awk中,處理動作中的字母若不用" "引上則表示使用變量,所以若需要輸出字符串則需要用“ ”引上。數字則不需要。

技術分享圖片
實例一、輸入分隔符

[root@centos6 ~]#echo {1..10}
1 2 3 4 5 6 7 8 9 10
[root@centos6 ~]#echo {1..10}|awk -v FS=" " ‘{print $1,$3}‘
1 3

??這裏表示原本輸出結果為1到時,拿FS內置變量舉例,設置空白字符為分隔符(默認分隔符就是空白字符,所以不指定結果也是一樣的,這裏只是為了舉例說明),取1,3列,
實例二、替換輸出分隔符

[root@centos6 ~]#echo {1..10} | awk -v OFS=":" ‘{print $1,$2,$3}‘
1:2:3

??這裏OFS內置變量表示將輸出結果分隔符變成:,取1,2,3列
實例三、分別顯示兩個文本的行號

[root@centos6 ~]#awk ‘{print FNR,$0}‘ /etc/fstab /etc/issue  #表示分別顯示每一個文件的行號
1 
2 #
3 # /etc/fstab
4 # Created by anaconda on Fri Mar  9 08:50:54 2018
5 #
6 # Accessible filesystems, by reference, are maintained under ‘/dev/disk‘
7 # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
8 #
9 /dev/mapper/vgentos6-LogVol03 / ? ? ? ? ? ? ? ? ? ? ? ext4 ?  defaults ? ? ? ?1 1
10 /dev/mapper/vgentos6-LogVol02 /app ? ? ? ? ? ? ? ? ?  ext4 ?  defaults ? ? ? ?1 2
11 UUID=8f86cc7e-f593-467d-b823-eae6610616a1 /boot ? ? ? ? ? ? ? ? ? ext4 ?  defaults ? ? ? ?1 2
12 /dev/mapper/vgentos6-LogVol00 /var ? ? ? ? ? ? ? ? ?  ext4 ?  defaults ? ? ? ?1 2
13 /dev/mapper/vgentos6-LogVol01 swap ? ? ? ? ? ? ? ? ?  swap ?  defaults ? ? ? ?0 0
14 tmpfs ? ? ? ? ? ? ? ? ? /dev/shm ? ? ? ? ? ? ?  tmpfs ? defaults ? ? ? ?0 0
15 devpts ? ? ? ? ? ? ? ?  /dev/pts ? ? ? ? ? ? ?  devpts ?gid=5,mode=620 ?0 0
16 sysfs ? ? ? ? ? ? ? ? ? /sys ? ? ? ? ? ? ? ? ?  sysfs ? defaults ? ? ? ?0 0
17 proc ? ? ? ? ? ? ? ? ?  /proc ? ? ? ? ? ? ? ? ? proc ?  defaults ? ? ? ?0 0
18 /dev/cdrom   /mnt/base   auto    defaults    0   0
1 CentOS release 6.9 (Final)
2 Kernel \r on an \m
3 

五、printf格式化輸出

??在輸出內容時,print輸出只能輸出規定格式的內容,不能自定義格式,所以想要讓輸出結果根據自己所需要的格式輸出就需要用printf來定制格式
printf使用格式
awk ‘{printf "格式1 格式 ",$1,$2}’,格式必須和需要輸出的列一一對應
技術分享圖片
實例一、格式化輸出,讓文本左對齊

[root@centos6 ~]#awk -F: ‘{printf "%-20s %-20d\n",$1,$3}‘ /etc/passwd
root ? ? ? ? ? ? ? ? 0 ? ? ? ? ? ? ? ? ? 
bin ? ? ? ? ? ? ? ? ?1 ? ? ? ? ? ? ? ? ? 
daemon ? ? ? ? ? ? ? 2 ? ? ? ? ? ? ? ? ? 
adm ? ? ? ? ? ? ? ? ?3 ? ? ? ? ? ? ? ? ? 
lp ? ? ? ? ? ? ? ? ? 4 ? ? ? ? ? ? ? ? ? 
sync ? ? ? ? ? ? ? ? 5 ? ? ? ? ? ? ? ? ? 
shutdown ? ? ? ? ? ? 6 ? ? ? ? ? ? ? ? ? 
halt ? ? ? ? ? ? ? ? 7 ? ? ? ? ? ? ? ? ? 
mail ? ? ? ? ? ? ? ? 8 ? ? ? ? ? ? ? ? ? 
uucp ? ? ? ? ? ? ? ? 10 ? ? ? ? ? 

? ??? ??因為printf不會自動換行,所以在規定好的格式後面增加\n來起到換行符的作用,其中-代表左對齊,若需要右對齊則直接填整數即可

六、awk運算符

??awk也可以進行數字間的運算,不但支持整數,而且支持小數
技術分享圖片
實例一、兩個數之間的運算

[root@centos6 ~]#awk ‘BEGIN{print 5+10}‘
15
[root@centos6 ~]#awk ‘BEGIN{print 5.5+10.5}‘
16
[root@centos6 ~]#awk ‘BEGIN{print 40/3}‘
13.3333

七、賦值運算

在賦值操作符中,sum+=i,就相當於sum=sum+i,
技術分享圖片
實例一、將100以內的數相加
seq 100 | awk ‘{sum+=$1}END{print sum}‘
5050
??因為awk本來就是針對行行的循環,可以根據這個特性將1到100相加在END部分將sum值輸出,就實現了100百以內數相加
實例二、變量的自增

[root@centos6 ~]#awk ‘{print i++}‘ /etc/passwd
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

? ? ? ?在awk中,變量一旦與運算符號結合使用,將認為該變量的初始值為0,這個這條語句表示從零開始/etc/passwd文件有多少行,i變量將自增幾次

八、模式匹配

??awk模式通配符~,表示左邊的內容是否和右邊內容匹配包含,!~則表示不匹配
實例一、在文件中查找包含某字符的行

[root@centos6 ~]#awk -F: ‘$0 ~ /root/{print $0}‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

??查看passwd這個文件包含root的行,並將其打印到終端
實例二、查找passwd文件中所有/bin/bash的行

[root@centos6 ~]#awk -F: ‘$0 ~ "/bin/bash"‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
lin:x:500:500::/home/lin:/bin/bash
hacker:x:501:501::/home/hacker:/bin/bash
test:x:502:502::/home/test:/bin/bash

??因所搜內容中也包含 ” / “ 所以需要將搜索內容用雙引號引起來

九、比較操作符

技術分享圖片

十、邏輯操作符

&&:表示同時滿足兩個條件
||:表示滿足兩個條件中的一個即可
!:表示取匹配結果的反值
實例一、取同時滿足兩個條件的結果&&

[root@centos6 ~]#awk -F: ‘$3>=50 && $3<=100{print $1,$3}‘ /etc/passwd
nobody 99
vcsa 69
postfix 89
sshd 74
tcpdump 72
dbus 81

實例二、去滿足一個或兩個條件的結果 ||

[root@centos6 ~]#awk -F: ‘$3>=50 || $3<=100{print $1,$3}‘ /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
uucp 10
operator 11
games 12
gopher 13
ftp 14
nobody 99
vcsa 69
saslauth 499
postfix 89
sshd 74
lin 500
tcpdump 72
hacker 501
dbus 81
test 502
apache 48

十一、條件表達式(三目表達式)

??常用於只有兩種情況下的判斷,如果情況過多,將不適合使用三目表達式來選擇
語法:判斷條件?條件為真時執行語句:條件為假時執行語句
實例一、將系統中所有用戶根據UID統計是系統用戶還是普通用戶 ? ? ? ? ? ? ? ? ? ? ??

[root@centos6 ~]#awk -F: ‘{$3>=500?usertype="common user":usertype="system user";print usertype,$1}‘ /etc/passwd
#根據UID判斷當前系統中所有用戶是系統用戶還是普通用戶
system user root
system user bin
system user daemon
system user adm
system user lp
system user sync
system user shutdown
system user halt
system user mail
system user uucp
system user operator
system user games
system user gopher
system user ftp
system user nobody
system user vcsa
system user saslauth
system user postfix
system user sshd
common user lin
system user tcpdump
common user hacker
system user dbus
common user test
system user apache

十二、PATTERN模式搜索

??該模式下也支持擴展正則表達式,支持模糊搜索
1.如果未指定,空模式,匹配每一行,默認搜索每一行
實例一

[root@centos6 ~]#awk ‘{print $0}‘ /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

2./指定匹配字符/:僅處理能夠模式匹配到的行需要用 / ?/ 括起來,若匹配的行關鍵字中也有/則需要使用\/來轉譯
實例一、只有滿足root為行首的行才會被匹配

[root@centos6 ~]#awk ‘/^root/{print $0}‘ /etc/passwd  #表示只匹配root為行首的行。
root:x:0:0:root:/root:/bin/bash

實例二、只要滿足r..o條件的將全部匹配

[root@centos6 ~]#awk ‘/r..t/{print $0}‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

3.關系表達式,若果為真才會被處理,
真:結果為非0值或非空值
假:結果為空字符串或0值
實例一、若條件為0或者空值時,則不會輸出任何結果

[root@centos6 ~]#awk ‘0{print}‘ /etc/passwd

實例二、若條件為非0或控制時,則打印結果

[root@centos6 ~]#awk ‘1{print}‘ /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

實例三、該表達式中,因為awk自帶行間的循環,又因為非空為1,當第一次非空則將賦值1給i則有結果輸出,第二次則將一個非1則為0,將0賦給i則第二個不輸出,依次類推則輸出結果如下

[root@centos6 ~]#seq 10 | awk ‘i=!i‘
1
3
5
7
9

4.行範圍,awk也能取匹配字符的行範圍 /匹配字符1/,/匹配字符2/處理動作

[root@centos6 ~]# awk ‘/^h/,/^f/‘ /etc/passwd
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
hacker:x:501:501::/home/hacker:/bin/bash
dbus:x:81:81:System message bus:/:/sbin/nologin
test:x:502:502::/home/test:/bin/bash
apache:x:48:48:Apache:/var/www:/sbin/nologin

? ? ? ? 當遇到以h為行首的行,則打印,到行首為f結束,因為打印完之後有碰到h為行首,則繼續打印,因為後面沒有h為行首,則一直打印到就結束

5.BEGIN/END模式
BEGIN{}:僅在開始處理文本之前執行一次
BEGIN屬於在文本執行前執行的語句塊,它不依賴於任何文件或輸出結果

[root@centos6 ~]#awk ‘BEGIN{print "test"}‘
test

END{}:僅在文本處理完成之後執行一次
END工作在awk處理完文本之後執行一次。可以用於打印pattern語句塊執行過程的結果
它也依賴於文件或輸出結果

[root@centos6 ~]#awk ‘END{print  "test"}‘ /etc/passwd
test

十三、awk控制語句

1.if else
語法

if(判斷條件){滿足條件執行的語句} [else {不滿足條件執行語句}
if(判斷條件1){滿足條件1執行語句}else if (判斷條件2{滿足條件2時執行語句}else{不
滿足上述兩個條件執行語句]

實例一、根據UID判斷系統中用戶是系統用戶還是普通用戶

[root@centos6 ~]#awk -F: ‘{if($3<=200){name="system"}else {name="user"} print $1,name}‘ /etc/passwd
root system
bin system
daemon system
adm system
lp system
sync system
shutdown system
halt system
mail system
uucp system
operator system
games system
gopher system
ftp system
nobody system
vcsa system
saslauth user
postfix system
sshd system
lin user
tcpdump system
hacker user
dbus system
test user
apache system

實例二、將20到30的數相加

[root@centos6 ~]#seq 50 |awk ‘{if($1>=20&&$1<=30){sum+=$1}}END{print sum}‘
275

?? 判斷系統中小於300的全部都是系統用戶,其他的全部為普通用戶
2.while循環
語法
{while (判斷條件){循環語句}},條件為真時,開始執行循環
??awk屬於行之間的循環,他不會對列進行循環,所以若需要對列進行計算和格式化處理,則需要使用awk內置循環來進行
實例一、將每一行的和輸出值終端

[root@centos6 ~]#cat test.txt ?
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
[root@centos6 ~]#awk ‘{sum=0;i=1;while(i<=NF){sum+=$i ;i++}print sum}‘ test.txt 
55
155

實例二、統計/boot/grub2/grub.conf文件中行首為linux16行每一個字段的字符數

[root@centos7 ~]# awk ‘/^[[:space:]]+linux/{i=1;while(i<=NF){print $i,length($i);i++}}‘ /boot/grub2/grub.cfg 
linux16 7
/vmlinuz-0-rescue-e8e8f687a3b24f13bda5566ae49855e6 50
root=UUID=7b231a1b-a730-40dd-ae89-4d565d07b340 46
ro 2
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-4.15.13.test 21
root=UUID=7b231a1b-a730-40dd-ae89-4d565d07b340 46
ro 2
rhgb 4
quiet 5
net.ifnames=0 13
LANG=en_US.UTF-8 16

? ? ? ? i作為自增項,循環條件為i<=字段數,length($i)內置函數,用於測量字段的長度?
3.do while
語法
do{循環語句}while(判斷條件),該語句與while唯一不同就是循環一定執行一次,不管判斷條件是否為真
4.for循環
語法
for(變量;判斷;變量自增){循環語句},其中()中必須是三部分組成
實例一、該實例和while實現的功能一直,只是寫法不同

[root@centos7 ~]# awk ‘/^[[:space:]]+linux16/{for(i=1;i<=NF;i++){print $i,length($i)}}‘ /boot/grub2/grub.cfg 
linux16 7
/vmlinuz-0-rescue-e8e8f687a3b24f13bda5566ae49855e6 50
root=UUID=7b231a1b-a730-40dd-ae89-4d565d07b340 46
ro 2
rhgb 4
quiet 5
net.ifnames=0 13
linux16 7
/vmlinuz-4.15.13.test 21
root=UUID=7b231a1b-a730-40dd-ae89-4d565d07b340 46
ro 2
rhgb 4
quiet 5
net.ifnames=0 13
LANG=en_US.UTF-8 16

十三、循環控制語句

break:直接跳出循環

[root@centos6 ~]#cat test.txt 
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
[root@centos6 ~]#awk ‘{for(i=1;i<=NF;i++){if($i%2==0){break}print $i}}‘ test.txt 
1
11

??因為當前文件中有兩行內容,則顯示兩個數,如果只有一行內容,則只顯示第一個數,因為當執行到2的時候跳出循環進入下次循環,而11以後則是下次循環,所以還會繼續執行
continue:退出這次循環,進入下次循環、

[root@centos6 ~]#cat test.txt 
1 2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
[root@centos6 ~]#awk ‘{for(i=1;i<=NF;i++){if($i%2==0){continue}print $i}}‘ test.txt 
1
3
5
7
9
11
13
15
17
19

當$i的值除以2 余數為0則跳出循環,其他則輸出
next:跳出當前行循環,進入下次行循環

[root@centos6 ~]#seq 10 |awk ‘{if($1%2==0){next}print $1}‘
1
3
5
7
9

next控制的是行間的調過,當該行滿足這個條件,則跳出這行循環,進入下次循環

十三、awk數組

awk中的數組只有關聯數組
1.可以使用任意字符串,字符串要使用雙引號括起來
2.如果某數組元素實現不存在,在引用時,awk會自動創建次元素,並將其值初始化為空字符串
語法
數組名["下標"]="參數"
數組可以用於統計某個字符串出現過幾次,用來統計次數
實例一、統計access_log文件每一個ip的訪問次數

[root@centos6 ~]#awk ‘{ip[$1]++}END{for(i in ip){print i,ip[i]}}‘ access_log 
172.18.250.183 81
172.18.251.149 158
172.18.0.223 12
172.18.251.21 81
172.18.251.122 52
172.18.254.6 1643
172.18.253.21 74087
172.18.251.150 34
172.18.252.134 514

十四、awk內置函數

length():返回指定字符串的長度

[root@centos6 ~]#echo abcde | awk ‘{print length($1)}‘
5

rand():返回0和1之間的隨機數,也就是小數在使用rand()函數時,在前面必須指定種子srand(),若想隨機整數,則需要乘以一個數(根據想要的位數)
[root@centos6 ~]#awk ‘BEGIN{srand();print int(rand()*10)}‘
int()也是函數,它的作用是取整數,當前命令會隨機取10以內的整數 ? ? ? ?
sub(r,s,[t]):對t字符串進行搜索r表示模式匹配的內容,並將第一個匹配的內容替換為s
gsub(r,s,[t]):對匹配的字符全局替換

[root@centos6 ~]#echo {1..10} | awk ‘gsub(" ",":",$0)‘
1:2:3:4:5:6:7:8:9:10

將空格全局替換成:
split(s,array,[r]):以r為分隔符,切割字符串s,並且將切割後的結果保存到array的數組中,第一個索引值為1

[root@centos6 ~]#awk ‘{split($5,c,":")};{ip[c[1]]++}END{for (i in ip){print $1,ip[i]}}‘ netstat.log 
tcp 13
tcp 3
tcp 1
tcp 1
tcp 1
tcp 1
tcp 1
tcp 1
tcp 1
tcp 1
tcp 1
tcp 1
tcp 1
tcp 1
tcp 15

十五、awk自定義函數,腳本調用

function name (虛變量1,虛變量2){
 ? ? ? ? ? ? ? ? ?  處理動作
 ? ? ? ? ? ? ? ? ?  處理動作
}

??虛變量指的是需要用戶輸入兩個變量,但是傳入函數執行的變量和函數本身變量名不一致,也可以理解成一種定義格式,必須指定兩個變量才可以調用該函數
awk程序也可以寫成腳本,然後當程序需要是,可以直接調用執行,awk腳本也是需要執行權限,所以在執行之前需要個執行權限
腳本格式

#!/bin/awk -f
腳本內容

實例一

#!/bin/awk -f
function biji (x,y){
 ? ? ? ?if(x>y){ max="x>y"}
 ? ? ? ?else if (x==y){max="x=y"}
 ? ? ? ?else{ max="x<y" }
 ? ? ?  return max
}
BEGIN{print biji(a,b)}
[root@centos6 ~]#awk -v a=7 -v b=7 -f test.awk 
x=y
[root@centos6 ~]#awk -v a=7 -v b=6 -f test.awk 
x>y
[root@centos6 ~]#awk -v a=5 -v b=6 -f test.awk 
x<y

十六、system命令

??在awk語句中,也可以根據需求調用系統的一些命令,但是要結合system內置函數來實現
語法
awk BEGIN‘system("系統命令")’

awk用法詳解