第一章
1.awk 简介
awk不仅仅时linux系统中的一个命令,而且是一种编程语言,可以用来处理数据和生成报告(excel)。处理的数据可以是一个或多个文件,可以是来自标准输入,也可以通过管道获取标准输入,awk可以在命令行上直接编辑命令进行操作,也可以编写成awk程序来进行更为复杂的运用。本章主要讲解awk命令的运用。
2.awk 的格式
- awk指令是由模式,动作,或者模式和动作的组合组成。
- 模式既pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把他理解为一个条件。
- 动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。比如awk使用格式
- pattern既模式,也可以理解为条件。
- action既动作,可以理解为干啥,找到人之后你要做什么
3.awk 内置变量
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符,等价于命令行 -F选项
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
此外,$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。
第二章 实战
[root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10{print NR,$1}' /etc/passwd
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator
[root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10{print $1}' /etc/passwd
lp
sync
shutdown
halt
mail
operator
[root@bogon ~]#
命令解释
-F 分隔符:
NR >=5 && NR<=10 这部分表示模式,是一个条件,表示取第5行到第10行。
{print NR,¥1} :表示输出行号和$1第一列
2. 只有模式
[root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10' /etc/passwd
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
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
命令解释:
这里少了动作:{print NR,$1} 所以就输出了 NR>=5 &&NR<=10 第5 -10 行
3. 只有动作
[root@bogon ~]# awk -F':' '{print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator
11 games
12 ftp
13 nobody
14 systemd-network
命令说明:
-F指定分隔符为冒号
这里没有条件,表示对每一行都处理
{print NR,$1}表示动作,显示NR行号与$1第一列
这里要理解没有条件的时候,awk会处理每一行。
4.多个模式和动作
[root@bogon ~]# awk -F":" 'NR==1{print NR,$1}' /etc/passwd
1 root
[root@bogon ~]# awk -F":" 'NR==1{print NR,$1}NR==2{print NR,$NF}' /etc/passwd
1 root
2 /sbin/nologin
[root@bogon ~]#
命令解释:
-F 以冒号为分隔符
这里有多个条件与动作的组合
NR==1表示条件,行号(NR)等于1的条件满足的时候,执行{print NR,$1}动作,输出行号与第一列。
NR==2表示条件,行号(NR)等于2的条件满足的时候,执行{print NR,$NF}动作,输出行号与最后一列($NF)
5.文件处里过程
[root@bogon ~]# awk 'NR>=2{print NR,$0}' /test/files/awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 operator:x:11:0:operator:/root:/sbin/nologin
[root@bogon ~]#
命令说明:
条件NR>=2,表示行号大于等于2时候,执行{print $0}显示整行。
awk是通过一行一行的处理文件,这条命令中包含模式部分(条件)和动作部分(动作),awk将处理模式(条件)指定的行
6.awk 小结
1)awk读入第一行内容
2)判断是否符合模式中的条件NR>=2
a,如果匹配则执行对应的动作{print $0}
b,如果不匹配条件,继续读取下一行
3)继续读取下一行
4)重复过程1-3,直到读取到最后一行(EOF:end of file)
第三章
1.记录和字段
接下来我给大家带来两个新概念记录和字段,这里为了方便大家理解可以把记录就当作行即记录==行,字段相当于列,字段==列。
名称 | 含义 |
---|---|
record | 记录,行 |
field |
域,区域,字段,列 |
2.
[root@bogon ~]# awk 'BEGIN{RS="/"}{print NR,$0}' /test/files/awkfile.txt
1 root:x:0:0:root:
2 root:
3 bin
4 bash
bin:x:1:1:bin:
5 bin:
6 sbin
7 nologin
daemon:x:2:2:daemon:
命令解释
在每行的开始先打印输出NR(记录号行号),并打印出每一行$0(整行)的内容。
我们设置RS(记录分隔符)的值为“/”,表示一行(记录)以“/”结束
在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些
(回车换行符),
也是字符哦。
[root@bogon ~]# awk 'BEGIN{RS="/"}{print NR,$0}' /test/files/awkfile.txt
1 root:x:0:0:root:
2 root:
3 bin
4 bash
bin:x:1:1:bin:
5 bin:
6 sbin
7 nologin
daemon:x:2:2:daemon:
8 sbin:
命令说明:
在每行的开始先打印输出NR(记录号行号),并打印出每一行$0(整行)的内容。
我们设置RS(记录分隔符)的值为“/”,表示一行(记录)以“/”结束
在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些
(回车换行符),
也是字符哦。
对$0的认识
- 如1.7.2的例子,可以看出awk中$0表示整行,其实awk使用$0来表示整条记录。记录分隔符存在RS变量中,或者说每个记录以RS内置变量结束。
- 另外,awk对每一行的记录号都有一个内置变量NR来保存,每处理完一条记录,NR的值就会自动+1
- 行(记录):默认以 (回车换行)结束。而这个行的结束不就是记录分隔符嘛。
- 所以在awk中,RS(记录分隔符)变量表示着行的结束符号(默认是回车换行).
[root@chensiqi1 ~]# awk '{print NR,$0}' /server/files/awkfile.txt
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
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
命令说明:
NR既number of record,当前记录的记录号,刚开始学也可以理解为行号。
$0表示整行或者说整个记录
第4章
实战1
[root@bogon ~]# echo "I am test,my qq is 222222">>/test/files/test.txt
[root@bogon ~]# cat /test/files/test.txt
I am test,my qq is 222222
[root@bogon ~]# awk -F "[ ,]" '{print $3,$NF}' /test/files/test.txt
test 222222
[root@bogon ~]# awk -F "[,]" '{print $3,$NF}' /test/files/test.txt
my qq is 222222
[root@bogon ~]#
命令解释:
通过命令-F参数指定区域分隔符
[ ,]是正则表达式里面的内容,它表示一个整体,“一个”字符,既空格或者逗号(,),合并在一起,-F “[ ,]”就表示以空格或者逗号(,)为区域分隔符
第5章
awk默认就支持的元字符:
元字符 | 功能 | 示例 | 解释 |
---|---|---|---|
^ | 字符串开头 | /^chensiqi/或$3~/^chensiqi/ | 匹配所有以chensiqi开头的字符串;匹配出所有第三列中以chensiqi开头的 |
$ | 字符串结尾 | /chensiqi$/或$3~/chensiqi$/ | 匹配所有以chensiqi结尾的字符串;匹配第三列中以chensiqi结尾的 |
.(点) | 匹配任意但个字符(包括回车符) | /c..l/ | 匹配字母c,然后两个任意字符,再以l结尾的行 |
* | 重复0个或多个前一个字符 | /a*cool/ | 匹配0个或多个a之后紧跟着cool的行 |
+ | 重复前一个字符一次或多次 | /a+b/ | 匹配一个或多个a加上字符串b的行 |
? | 匹配0个或一个前边的字符 | /a?b/ | 匹配以字母a或b或c开头的行 |
[] | 匹配指定字符组内的任一个字符 | /^[abc]/ | 匹配以字母a或b或c开头的行 |
[^] | 匹配不在指定字符组内的任一字符 | /^[^abc]/ | 匹配不以字母a或b或c开头的行 |
() | 子表达式组合 | /(chensiqi)+/ | 表示一个或多个cool组合,当有一些字符需要组合时,使用括号括起来 |
| |
或者的意思 | /(chensiqi)|B/ |
匹配chensiqi或字母B的行 |
awk默认不支持的元字符:(参数--posix)
元字符 | 功能 | 示例 | 解释 |
---|---|---|---|
x{m} | x字符重复m次 | /cool{5}/ | 匹配l字符5次 |
x{m,} | x字符重复至少m次 | /(cool){2,}/ | 匹配cool整体,至少2次 |
x{m,n} | x字符重复至少m次,但不超过n次 | /(cool){5,6}/ | 匹配cool整体,至少5次,最多6次 |
提示:
- 加括号代表整体匹配,不加那么就匹配前边的一个字符。awk默认不支持这种形式的正则,需要加--posix参数或者--re-interval
- 正则表达式的运用,默认是在行内查找匹配的字符串,若有匹配则执行action操作,但是有时候仅需要固定的列来匹配指定的正则表达式,比如:我想取/etc/passwd文件中第五列{$5}这一列查找匹配mail字符串的行,这样就需要用另外两个匹配操作符,并且awk里面只有这两个操作符来匹配正则表达式。
实在1
[root@bogon ~]# awk -F":" '$0~/^root/' /test/files/awkfile.txt
root:x:0:0:root:/root:/bin/bash
[root@bogon ~]# cd /test/files/
[root@bogon files]# ls
awkfile.txt count.txt ip.txt test.txt
[root@bogon files]# awk -F":" '/^root/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
[root@bogon files]#
命令解释
awk只用正则表达式的时候是默认匹配整行的即‘$0~/^root/’和‘/^root/’是一样的。
实战2
匹配其中某一行
[root@bogon files]# awk -F ":" '$5~/shutdown/' awkfile.txt
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
[root@bogon files]#
第6章
文件测试
[root@bogon files]# cat >>/test/files/reg.txt<<KOF
> 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
> KOF
说明:
- 第一列是姓氏
- 第二列是名字
- 第一列第二列合起来就是姓名
- 第三列是对应的ID号码
- 最后三列是三次捐款数量
2.2.7 awk正则表达式练习题
练习题1:显示姓Zhang的人的第二次捐款金额及她的名字
练习题2:显示Xiaoyu的名字和ID号码
练习题3:显示所有以41开头的ID号码的人的全名和ID号码
练习题4:显示所有以一个D或X开头的人名全名
练习题5:显示所有ID号码最后一位数字是1或5的人的全名
练习题6:显示Xiaoyu的捐款,每个值都有以$开头。如$520$200$135
练习题7:显示所有人的全名,以姓,名的格式显示,如Meng,Feixue
练习题1
示例1:显示姓Zhang的人的第二次捐款金额及她的名字
[root@bogon files]# awk -F "[ :]+" '$1~/^Zhang/{print $1,$2,$5}' reg.txt
Zhang Dandan 100
Zhang Xiaoyu 90
[root@bogon files]#
或者
awk -F "[ :]+" '$1~/^Zhang/{print $2,$(NF-1)}' reg.txt
说明:
- -F指定分隔符,现在大家知道了-F即FS也是支持正则表达式的。
- 【 :】+ 表示连续的空格或冒号
- -F “【 :】+” 以连续的空格或冒号为分隔符
- /Zhang/表示条件,整行中包含Dan字符的这个条件。
- {print $1,$(NF-1)} 表示动作,满足条件后,执行显示第一列($1)和倒数第二列($(NF-1))当然$5也可以。
注意:
NF是一行中有多少列,NF-1整行就是倒数第二列。
$(NF-1)就是取倒数第二列内容。
练习题二
练习题2:显示Xiaoyu的名字和ID号码
[root@bogon files]# awk '/Xiaoyu/{print $1,$3}' reg.txt
Zhang 390320151
[root@bogon files]#
或者
awk -F "[ :]+" '$2~/^Xiaoyu/{print $1,$3}' reg.txt
命令说明:
指定分隔符-F “【:】+”
$2~/Xiaoyu/表示条件,第二列包含Xiaoyu时候执行对应的动作
{print $1,$3}表示动作,显示第一列和第三列的内容
练习三
练习题3:显示所有以41开头的ID号码的人的全名和ID号码
[root@bogon files]# awk '$0~/41/' reg.txt
Zhang Dandan 41117397 :250:100:175
Liu Bingbing 41117483 :250:100:175
[root@bogon files]# awk '$0~/41/{print $1,$2,$3}' reg.txt
Zhang Dandan 41117397
Liu Bingbing 41117483
[root@bogon files]# awk '$3~/41/{print $1,$2,$3}' reg.txt
Zhang Dandan 41117397
Liu Bingbing 41117483
[root@bogon files]#
练习题4:显示所有以一个D或X开头的人名全名
[root@bogon files]# awk -F "[ :]+" '$2~/^D|^X/{print $1,$2}' reg.txt
Zhang Dandan
Zhang Xiaoyu
Wang Xiaoai
[root@bogon files]#
命令说明:
-F “【 :】+”指定分隔符
|表示或,^以...开头
示例5:显示所有ID号码最后一位数字是1或5的人的全名
[root@bogon files]# awk '$3~/1$|5$/{print $1,$2}' reg.txt
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai
[root@bogon files]# awk -F"[ :]+" '$3~/1$|5$/{print $1,$2}' reg.txt
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai
[root@bogon files]#
示例6:显示Xiaoyu的捐款,每个值都有以$开头。如$520$200$135
[root@bogon files]# awk -F"[ :]+" '$2~/Xiaoyu/{print "$"$4"$"$5"$"$6}' reg.txt
$155$90$201
[root@bogon files]#
示例7:显示所有人的全名,以姓,名的格式显示,如Meng,Feixue
[root@bogon 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
[root@bogon files]#
实例8 :取出网卡eth0的ip地址
[root@bogon files]# ip addr |awk -F "[ /]+" 'NR==9{print $3}'
192.168.1.111
[root@bogon files]#
第7章
正侧扩展
[root@bogon files]# echo "---===1###2"
---===1###2
[root@bogon files]# echo "---===1###2" |grep "[-=#]"
---===1###2
[root@bogon files]# echo "---===1###2" |grep -o "[-=#]"
-
-
-
=
=
=
#
#
#
[root@bogon files]#
awk正则之{} -花括号
awk中的花括号有些不常用,但是偶尔会用到这里简单介绍。
示例:取出awkfile中第一列包含一个o或者两个o的行
[root@bogon files]# awk -F":" '$1~/o{1,2}/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
operator:x:11:0:operator:/root:/sbin/nologin
[root@bogon files]#
[root@bogon files]# awk -F: --re-interval '$1~/o{1,2}/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
operator:x:11:0:operator:/root:/sbin/nologin
2.实例
取出常用的服务端口
[root@bogon files]# awk -F "[ /]+" '$1~/^(ssh)$|^(http)$|^(https)$|^(mysql)$|^(ftp)$/{print $1,$2}' /etc/services |sort |uniq
ftp 21
http 80
https 443
mysql 3306
ssh 22
[root@bogon files]#
- |是或者的意思,正则表达式
- sort是将输出结果排序
- uniq是去重复但不标记重复个数
- uniq -c去重复但标记重复个数
实例3
说明:
条件:从第三列以bin开头字符串的行到第三列以lp开头字符串的行
动作:显示行号和整行
[root@bogon files]# awk '/^bin/,NR==5{print NR,$0}' awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
示例4
awk -F":" '$5~/^bin/,/^lp/{print NR,$0}' awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
说明:
条件:从第五列以bin开头的行到以lp开头的行
动作:显示行号和正航内容
合起来:从第三列以bin开始的行到以lp开头的行并显示其行号和整行内容
第九章
BEGIN 用法
[root@bogon files]# awk -F":" 'BEGIN{print "username","UID"}{print $1,$3}' awkfile.txt
username UID #
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
[root@bogon files]#
说明:
要在第一行输出一些username和UID,我们应该想到BEGIN{}这个特殊的条件(模式),因为BEGIN{}在awk读取文件之前执行的。
所以结果是BEGIN{print "username","UID"}
,注意print命令里面双引号吃啥吐啥,原样输出。
然后我们实现了在输出文件内容之前输出“username”和“UID”,下一步输出文件的第一列和第三列即{print $1,$3}
最后结果就是BEGIN{print "username","UID"}{print $1,$3}
2/使用BEGIN模块的特殊性质,进行一些测试。
[root@www files]#简单输出内容: [root@www files]# awk 'BEGIN{print "hello world!"}'
hello world!
[root@www files]# #进行计算
[root@www files]# awk 'BEGIN{print 10/3}'
3.33333
[root@www files]# awk 'BEGIN{print 10/3+1}'
4.33333
[root@www files]# awk 'BEGIN{print 10/3+1/4*9}'
5.58333
[root@www files]# #和变量有关的操作
[root@www files]# awk 'BEGIN{a=1;b=2;print a,b}'
1 2
[root@www files]# awk 'BEGIN{a=1;b=2;print a,b,a+b}'
1 2 3
企业案例:统计/etc/servies文件里的空行数量
思路:
a)空行通过正则表达式来实现:^$
b)统计数量:
- grep -c
- awk
方法一:grep
grep "^$" /etc/services | wc -l
16
grep -c "^$" /etc/services
16
说明:
grep命令-c表示count计数统计包含^$的行一共有多少。
方法二:
awk '/^$/{i++}END{print i}' /etc/services
16
提示:
使用了awk的技术功能,很常用
第一步:统计空行个数
/^$/
表示条件,匹配出空行,然后执行{i++}(i++等于i=i+1)即:/^$/{i=i+1}
我们可以通过/^$/{i=i+1;print i}
来查看awk执行过程
wk '/^$/{i=i+1;print "the value of i is:"i}' /etc/services
the value of i is:1
the value of i is:2
the value of i is:3
the value of i is:4
the value of i is:5
the value of i is:6
the value of i is:7
the value of i is:8
the value of i is:9
the value of i is:10
the value of i is:11
the value of i is:12
the value of i is:13
the value of i is:14
the value of i is:15
the value of i is:16
第二步:输出最后结果
- 但是我们只想要最后的结果16,不想要过程怎么办?使用END模式输出结果
- 因为END模式的特殊性质所以很适合输出最终结果
所以最终结果就是awk '/^$/{i=i+1}END{print "blank lines count:"i}' /etc/services
awk编程思想:
- 先处理,最后再END模块输出
{print NR,$0}body
模块处理,处理完毕后END{print "end of file"}
输出一个结果
企业面试题5:文件count.txt,文件内容是1到100(由seq 100生成),请计算文件每行值加起来的结果(计算1+...+100)
思路:
文件每一行都有且只有一个数字,所以我们要让文件的每行内容相加。
回顾一下上一道题我们用的是i++即i=i+1
这里我们需要使用到第二个常用的表达式
i=i+$0
对比一下,其实只是把上边的1换成了$0
awk '{i=i+$0}END{print i}' count.txt
5050