04.21 三剑客之老大awk命令详解
第一章 awk执行过程
1. awk版本信息
[root@Never-downtime ~]# awk --version
GNU Awk 3.1.7
2. awk参数模式动作
模式既pattem,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。
比如NR==1,这就是模式,可以把他理解为一个条件。
动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。如下awk使用格式。
3. awk执行过程
1读取一行>>
2根据模式/条件判定是否是要处理的行(NR>=2)>>
3如果不是则读取下一行,直到文件的结尾>>
4如果是对读取的行进行动作(action)处理>>
5处理完了继续读取文件的下一行 重复操作直至文件末尾。
第二章 awk记录和字段
1. 行和列
接下来我们给大家带来两个新概念记录和字段,这里为了方便大家理解可以把记录就当做行即记录==行,字段相当于列,字段==列。
名称 | 含义 |
---|---|
record | 记录、行 |
field | 域、区域、字段、列 |
awk默认情况下每一行都是一个记录(record)
RS即record separator输入数据记录分隔符,每一行是怎么没的,表示每个记录输入的时候的分隔符,即行与行之间如何分割。
NR即number of record记录(行)号,表示当前正在处理的记录(行)的号码。
ORS即output record separator输出记录分隔符。
awk使用内置变量RS来存放输入记录分隔符,RS表示的输入的记录分隔符,这个值可以通过BEGIN模块重新定义修改。
[root@Never-downtime files]# cat awkfile.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
awk 'BEGIN{RS="/"}{print NR,$0}' awkfile.txt
2. awk记录知识小结
NR(number of record)存放着每个记录的号(行号)读取新行时候会自动+1
RS(record separator)是输入数据的记录/行标志,简单理解就是可以指定每个记录的结尾标志。RS作用就是表示一个记录的结束。
当我们修改了RS的值,最好配合NR行来查看变化,也就是修改了RS的值通过NR查看结果,调试awk程序。
ORS输出数据的记录的分隔符。可以通过修改RS的值,然后配合NR(行)来查看变化,也就是修改了RS的值通过NR查看结果,调试awk程序。
3. 字段(列)
每条记录都是由多个区域(field)组成的,默认情况区域之间的分隔符是由空格(即空格或制表符)来分隔,并且将分隔符记录在内置变量FS中,每行记录的区域数保存在awk的内置变量NF中。
4. FS与OFS
(1)FS即field separator,输入字段(列)分隔符。分隔符就是菜刀,把一定字符串切位很多个区域。
(2)awk -F 实际上修改的就是FS的内容,相当于 awk ‘BEGIN{FS=”:”}’
(3)NF即number of fileds,表示一行中列(字段)的个数,可以理解为菜刀切过一行后,切成了多少份。
(4)OFS输出字段(列)分隔符。
(5)awk使用内置变量FS来记录区域分隔符的内容,FS可以在命令行上通过-F参数来更改,也可以通过BEGIN模块来更改。
(6)然后通过
5. 记录与字段(行与列)小结
小结 |
---|
RS记录分隔符,表示每行的结束标志。 |
NR行号(记录号) |
FS字段分隔符,每列的分隔标志或结束标志。 |
NF就是每行有多少列,每个记录中字段的数量。 |
$符号表示取某个列(字段),$1,$2,$NF |
NF(number of field)表示记录中的区域(列)数量,$NF取最后一个列(区域) |
FS 字段(列)分隔符, awk -F “:” ===== awk ‘BEGIN{FS=”:”}’ |
NR number of record 行号 |
分隔符就是结束标识 |
记录与区域,就是所谓的行与列 即(RS,FS) |
第三章 awk正则匹配操作符
awk 正则匹配操作符 | 含义 |
---|---|
~ | 用于对记录或区域的表达式进行匹配 |
!~ | 用于表达与~相反的意思 |
1. 案例
处理文件test.txt内容,将域名取出并根据域名进行计数排序处理
http://www.etiantian.org/index.html
http://www.etiantian.org/1.html
http://post.etiantian.org/index.html
http://mp3.etiantian.org/index.html
http://www.etiantian.org/3.html
http://post.etiantian.org/2.html
[aaa@qq.com files]# awk -F/ '{print $3}' test.txt |egrep -o [a-zA-Z0-9]|sort|uniq -c
1 3
12 a
6 e
6 g
12 i
1 m
12 n
8 o
3 p
6 r
2 s
14 t
9 w
2. 环境搭建
mkdir -p /server/files/
cat >>/server/files/reg.txt<<EOF
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
Meng Feixue 80042789 :250:60:50
Wu Waiwai 70271111 :250:80:75
Liu Bingbing 41117483 :250:100:175
Wang Xiaoai 3515064655 :50:95:135
Zi Gege 1986787350 :250:168:200
Li Youjiu 918391635 :175:75:300
Lao Nanhai 918391635 :250:100:175
EOF
3. 显示姓Zhang的人的第二次捐款金额及她的名字
[aaa@qq.com8 files]# awk -F "[ :]+" 'NR<=2{print $2,$(NF-1)}' reg.txt
Dandan 100
Xiaoyu 90
[aaa@qq.com8 files]# awk -F "[ :]+" '/^Zhang/{print $2,$(NF-1)}' reg.txt
Dandan 100
Xiaoyu 90
4. 显示Xiaoyu的姓氏和ID号码
[root@Never-downtime files]# awk 'NR==2{print $1,$3}' reg.txt
Zhang 390320151
[root@web02-8 files]# awk '/Xiaoyu/{print $1,$3}' reg.txt
Zhang 390320151
5. 显示所有以41开头的ID号码的人的全名和ID号码
[aaa@qq.com8 files]# awk '$3~/^41/{print $1,$2,$3}' reg.txt
Zhang Dandan 41117397
Liu Bingbing 41117483
6. 显示所有以一个D或X开头的人名全名
[aaa@qq.com8 files]# awk '$2~/^[DX]/{print $1,$2}' reg.txt
Zhang Dandan
Zhang Xiaoyu
Wang Xiaoai
7. 显示所有ID号码最后一位数字是1或5的人的全名
[aaa@qq.com8 files]# awk '$3~/[15]$/{print $1,$2}' reg.txt
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai
[aaa@qq.com8 files]# awk '$(NF-1)~/1$|5$/{print $1,$2}' reg.txt
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai
8. 显示Xiaoyu的捐款.每个值时都有以$开头.如$520$200$135
[root@web02-8 files]# awk 'BEGIN{FS=":" ;OFS="$"}NR==2{print "$"$2,$3,$NF}' reg.txt
$155$90$201
[root@web02-8 files]# awk -F ":" '/Xiaoyu/{print "$"$2"$"$3"$"$4}' reg.txt
$155$90$201
[root@web02-8 files]# awk 'NR==2{gsub(/:/,"$");print $NF}' reg.txt
$155$90$201
9. 显示所有人的全名,以姓,名的格式显示,如Meng,Feixue
[root@Never-downtime files]# awk 'BEGIN{OFS=","}{print $1,$2}' reg.txt
Zhang,Dandan
Zhang,Xiaoyu
Meng,Feixue
Wu,Waiwai
Liu,Bingbing
Wang,Xiaoai
Zi,Gege
Li,Youjiu
Lao,Nanhai
[root@Never-downtime files]# awk '{print $1","$2}' reg.txt
Zhang,Dandan
Zhang,Xiaoyu
Meng,Feixue
Wu,Waiwai
Liu,Bingbing
Wang,Xiaoai
Zi,Gege
Li,Youjiu
Lao,Nanhai
第四章 BEGIN模式
BEGIN{}模块在awk读取文件之前就执行,一般用来定义我们的内置变量(预定义变量,eg,FS,RS),可以输出表头
BEGIN模式之前我们有在示例中提到,自定义变量,给内容变量复制等,都使用过。需要注意的是BEGIN模式后面要接一个action动作操作,包含在大括号内。awk必须在对输入文件进行任何处理前先执行BEGIN里的动作(action)。
我们可以不要任何输入文件,就可以对BEGIN模块进行测试,因为awk需要先执行完BEGIN模式,才对输入文件做处理。BEGIN模式常常被用来修改内置变量ORS、RS、FS、OFS等的值。
1. 读取文件前执行
[aaa@qq.comNever-downtime files]# awk -F ":" 'BEGIN{print "NAME","UID"}{print $1,$3}' awkfile.txt |column -t
NAME UID
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
uucp 10
2.作用1:定义变量内容
例如RS、ORS、FS/—F 、OFS
[aaa@qq.com files]# awk 'BEGIN{name="hello";print name}'
hello
3. 作用2:计算器
[root@Never-downtime files]# awk 'BEGIN{print 10/3}'
3.33333
4. 取eth0的ip
[aaa@qq.com files]# ifconfig eth0 |awk -F "(addr:)|(Bcast:)" 'NR==2{print $2}'
192.168.56.129
[aaa@qq.com files]# ifconfig eth0 |awk -F "[ :]+" 'NR==2{print $4}'
192.168.56.129
[aaa@qq.com files]# ifconfig eth0 |awk -F "[^0-9.]+" 'NR==2{print $2}'
192.168.56.129
[aaa@qq.com files]# ifconfig eth0|awk 'BEGIN{FS="(addr:)|(Bcast:)"}NR==2{print $2}'
192.168.56.129
[aaa@qq.com files]# ifconfig eth0|awk 'BEGIN{FS="[ :]+"}NR==2{print $4}'
192.168.56.129
[aaa@qq.com files]# ifconfig eth0|awk 'BEGIN{FS="[^0-9.]+"}NR==2{print $2}'
192.168.56.129
第五章 END模式
END在awk读取完所有的文件的时候,再执行END模块,一般用来输出一个结果(累加,属组结果),也可以是和BEGIN模块类似的结尾表示信息。
1.统计文件有多少行
[root@web02-8 files]# awk '{i=i+1;print i}' reg.txt
1
2
3
4
5
6
7
8
9
[root@web02-8 files]# awk '{i=i+1}END{print i}' reg.txt
9
[root@Never-downtime files]# cat -n reg.txt |tail -1
9 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
[root@Never-downtime files]# sed -n 'p' reg.txt |wc -l
9
第六章 awk执行过程
(1)命令行的赋值(-F或-v)
(2)执行BEGIN模式里面的内容
(3)开始读取文件
(4)判断条件(模式)是否成立
(5)成立则执行对应动作里面的内容
(6)读取下一行,循环判断
(7)直到读取到最后一个文件的结尾
(8)最后执行END模式里面的内容
[root@Never-downtime files]# a=1
[root@Never-downtime files]# b=2
[root@Never-downtime files]# awk 'BEGIN{print a+b}'
0
[root@Never-downtime files]# awk -v a=1 -v b=2 'BEGIN{print a+b}'
3
[root@Never-downtime files]# awk -v a=$(hostname) 'BEGIN{print a}'
Never-downtime
第七章 awk属组
变量相当于一室的房子,每次只能住一家人,如果想往里面放很多种不同的内容,或者住不同的家庭,就需要用到多个变量,可以这不是很方便。所以公寓诞生了,即awk数组。
[aaa@qq.com files]# awk 'BEGIN{hotel[110]="xioyu";hotel[119]="bingbing";hotel[401]="tandao";for (pol in hotel) print pol,hotel[pol]}'
110 xioyu
401 tandao
119 bingbing
[aaa@qq.com8 files]# awk 'BEGIN{h[110]="xiaoyu";h[119]="bingbing";h[401]="tandao";for (a in h)print a,h[a]}'
119 bingbing
110 xiaoyu
401 tandao
awk属组总结
(1)awk数组是分析日志最常用的功能,也是玩转awk必会的部分。
(2)awk数组的名字就像九点的名字一样,学习的时候我们可以用hotel,h等等,后面再使用的时候要命名规范一些,要不再次使用的时候就不理解了。
(3)awk数组的元素名字就像房间号码,房间号码用的一般就是你想要处理的东西,比如统计ip地址,比如统计url。可以把ip,url作为房间号码。
(4)遇到awk数组的元素的内容就像房间里面住的人,一般就是放我们想要的结果,或者计算的结果,即把计算结果放在房间中,
(5)遇到awk数组的处理一般都是进行统计,这时候我们会把最后的结果在END模块里面输出。
(6)输出awk数组的结果,就是现实房间里面的内容,即查房。
(7)awk的查房是通过for (pol in hotel)这种形式来完成的,fot表示循环,pol表示警察是一个变量名字,in表示去查房,hotel表示酒店名称,合起来就是警察去酒店查房, 查完一个继续查下一个。
(8)在查房过程中pol警察知道房间号码,也就是说pol变量中的内容就是房间号码。
(9)要看房间中的内容,首先要知道酒店名称,然后就是房间号码即hotel[pol]。
(10)要熟练使用awk数组在开始的时候就要学会一步一步看awk如何执行的即可。
碰到问题先拆解:大象放冰箱一步一步来
第一个里程碑##取出想要的内容
第二个里程碑##创建数组
第三个里程碑##进行统计
扩展案例
假如现在有个文本,格式如下:
a 1
b 3
c 2
d 7
b 5
a 3
g 2
f 6
d 9
即左边是随机字母,右边是随机数字,要求写个脚本使其输出格式为:
a 4
b 8
c 2
d 16
f 6
g 2
即将相同的字母后面的数字加在一起,按字母的顺序输出。
[aaa@qq.com8 files]# awk '{AA[$1]=AA[$1]+$2}END{for (a in AA)print a,AA[a]}' test.txt
a 4
b 8
c 2
d 16
f 6
g 2