第1章 awk命令基础
1.1 awk命令执行过程
1、如果BEGIN 区块存在,awk执行它指定的动作。
2、awk从输入文件中读取一行,称为一条输入记录。如果输入文件省略,将从标准输入读取
3、awk将读入的记录分割成字段,将第1个字段放入变量$1中,第2个字段放入$2,以此类推。$0表示整条记录。字段分隔符使用shell环境变量FS或由参数指定。
4、把当前输入记录(数据行)依次与每一个awk命令中awk条件比较,看是否匹配,如果相匹配,就执行对应的动作。如果不匹配,就跳过对应的动作,直到比较完所有的awk命令。
5、当一条输入记录比较了所有的awk命令后,awk读取输入的下一行,继续重复步骤3和4,这个过程一直持续,直到awk读取到文件尾。
6、当awk读完所有的输入行后,如果存在END,就执行相应的动作。
1.2 awk中模式与动作
'pattern{action}'
1.2.1 在awk眼中的行与列
field 字段,列
record 记录,行
1.3 awk默认有一把“菜刀”
空格系列 (单独的空格,连续的空格,tab键)
-F 指定分隔符
-vFS
FS == field sep 每一列的分隔符
OFS ==output field sep 输出每一列的时候使用的分隔符
1.4 awk的内置变量
变量 | 含义 | 英文全写 |
FS | 每一列的分隔符 | field sep |
NF | 每一行有多少列 | number of field |
OFS | 输出每一列的时候使用的分隔符 | output field sep |
NR | 记录号 行号 | number of record |
RS | 每一行的分隔符(每一行的结束标记) |
|
$数字 | 取某一列 |
|
$0 | 取出这一行 |
|
1.4.1 $NF的使用
$NF 表示最后一列,(NF-1)表示倒数第二列,以此类推。
[root@znix ~]# awk -F: '{print NF}' passwd.txt
7
7
……
[root@znix ~]# awk -F: '{print $NF}' passwd.txt
/bin/bash
/sbin/nologin
/sbin/nologin
[root@znix ~]# awk -F: '{print $(NF-1)}' passwd.txt
/root
/bin
/sbin
1.5 【练习题】awk如何使用正则?
1) 显示Xiaoyu的姓氏和ID号码
2) 显示所有ID号码最后一位数字是1或5的人的全名
3) 姓氏是Zhang的人,显示他的第二次捐款金额及她的名字
4) 显示Xiaoyu的捐款.每个值时都有以$开头.如$520$200$135
1.5.1 环境准备
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
1.5.1.1 内容释义:
第一列是姓氏
第二列是名字
第一第二列合起来就是姓名
第三列是对应的ID号码
最后三列是三次捐款数量
1.5.2 显示出第二列中包含X 的。
$2~表示第二列所有的内容。 ~表示所有
在这里X比较特殊,是大写的,awk中区分大小写。
[root@znix files]# awk '$2~/X/' reg.txt
Zhang Xiaoyu 390320151 :155:90:201
Wang Xiaoai 3515064655 :50:95:135
1.5.3 显示Xiaoyu的姓氏和ID号码
[root@znix files]# awk '$2~/Xiaoyu/{print $1,$3}' reg.txt
Zhang 390320151
1.5.4 显示所有ID号码最后一位数字是1或5的人的全名
[root@znix files]# awk '$3~/(1|5)$/{print $1,$2}' reg.txt
[root@znix files]# awk '$3~/[15]$/{print $1,$2}' reg.txt
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai
1.5.5 姓氏是Zhang的人,显示他的第二次捐款金额及她的名字
先找到,再进行输出。(NF-1) 表示倒数第二列。
[root@znix files]# awk -F "[ :]+" '$1~/Zhang/{print $2,$(NF-1)}' reg.txt
Dandan 100
Xiaoyu 90
1.5.6 显示Xiaoyu的捐款.每个值时都有以$开头.如$520$200$135
tr 命令进行替换,格式比较简单tr "要替换什么" "替换成什么"
[root@znix files]# awk '$2~/Xiaoyu/{print $4}' reg.txt |tr ":" "$"
$155$90$201
[root@znix files]# awk '$2~/Xiaoyu/{gsub(/:/,"$",$NF);print $NF}' reg.txt
$155$90$201
1.6 awk中的$0是什么鬼?
$0表示文件中整条记录(行)的内容,在这里加$0 与不加$0 相同。
[root@znix files]# awk '/Zhang/' reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
[root@znix files]# awk '$0~/Zhang/' reg.txt
Zhang Dandan 41117397 :250:100:175
Zhang Xiaoyu 390320151 :155:90:201
1.7 awk中的替换
在awk中,可以用来替换的有三个函数:sub gsub gensub
1.7.1 使用gusb 函数进行替换
gsub(r, s [, t])
r /找谁/
s "替换成什么"
[] 替换那个部分的
表示为: gsub(/找谁/,"替换成什么",替换那个部分的)
1.7.2 替换文本中的内容
题目:显示Xiaoyu的捐款.每个值时都有以$开头.如$520$200$135
中间使用分号分割 ;
[root@znix files]# awk '{gsub(/:/,"$",$NF);print $0}' reg.txt
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
添加上限定条件后,取到的结果会更加的精确。
[root@znix files]# awk '$2~/Xiaoyu/{gsub(/:/,"$",$NF);print $NF}' reg.txt
$155$90$201
1.8 【练习题】判断当前系统上所有用户的shell是否为可登录shell(即用户的shell不是/sbin/nologin),如果是显示用户名字
不包含:!,在awk中不包含可以使用! 表示。
$NF 表示这个文件的最后一列
-F 将分隔符指定为:
[root@znix ~]# awk -F: '$NF!~/nologin$/{print $1}' /etc/passwd
root
sync
shutdown
halt
oldboy
oldgirl
test
stu01
stu02
stu03
znix
1.8.1 【对齐】输出的结果更美观整齐--column命令
-t -t参数让他对齐。
[root@znix files]# awk 'BEGIN{print "姓","名"}{print $1,$2}' reg.txt |column -t
姓 名
Zhang Dandan
Zhang Xiaoyu
Meng Feixue
Wu Waiwai
Liu Bingbing
Wang Xiaoai
Zi Gege
Li Youjiu
Lao Nanhai
第2章 awk中BEGIN 和 END
2.1 怎么把正则表达式作为条件
BEGIN:开始
里面的内容会在awk读取文件之前运行
在BEGIN里面定义awk的内置变量
END
END{} 里面放入内容,在读取完文件内容后执行
先计算,在END里面输出结果
先计算再输出
2.1.1 【一个栗子】执行完输出后,再输出一个“结束”
[root@znix files]# awk '{print $0}END{print "结束"}' reg.txt
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
结束
2.2 【企业案例】统计/etc/services文件里面的空行数量
2.2.1 使用awk的END模式
前面的i++先进行计算,再输出结果。
i=i+1 与i++ 相同。
[root@znix ~]# awk '/^$/{i=i+1}END{print i}' /etc/services
16
[root@znix ~]# awk '/^$/{i++}END{print i}' /etc/services
16
2.2.2 查看i++的执行过程
i++与i=i+1相同。
i=i+$0 累计相加 计算总和
i=i+1 i++ 计数
[root@znix ~]# awk '/^$/{i++;print i}' /etc/services
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2.2.3 其他方法:
uniq -c uniq 命令把相邻两行一样的合并,-c为统计出现的次数
[root@znix ~]# awk '/^$/' /etc/services|uniq -c
16
[root@znix ~]# awk '/^$/' /etc/services|wc -l
16
2.3 【案例】seq 100 >num.txt ,计算这个文件每一行相加的结果
i=i+$0 累计相加 计算总和
i=i+1 i++ 计数
没有赋初始值的时候
i++ 先返回0,再加1,第二次调用的时候先返回1,再加1,以此类推
[root@znix ~]# awk '{i=i+$0}END{print i}' num.txt
5050
第3章 awk数组
3.1 数组是用来做什么的?
分类计算,用于统计。
3.1.1 他能够干些什么?
统计日志文件中 图片.jpg 出现了多少次
统计日志文件中 图片.png 出现了多少次
统计更累的信息
3.2 数组详解---"老男孩酒店"
假设我们的酒店叫老男孩教育酒店
老男孩教育酒店<===>hotel
酒店里面有几个房间110,119,120,114,401这几个房间。
老男孩教育酒店的110房间<===> hotel[110]
老男孩教育酒店的119房间<===> hotel[119]
老男孩教育酒店的120房间<===> hotel[121]
酒店房间里面入住客人
3.2.1 如何查看房间里住的是哪位客人?
[root@znix files]# awk 'BEGIN{hotel[110]="lidao" ;hotel[119]="tanjiaoshou";hotel[121]="taojin";print hotel[110],hotel[121],hotel[119]}'
lidao taojin tanjiaoshou
3.2.2 使用for语句,对酒店进行循环/查房
awk 'BEGIN{hotel[110]="lidao" ;hotel[119]="tanjiaoshou";hotel[121]="taojin";
for(pol in hotel)
print pol,hotel[pol]
}'
格式:
for(变量 in 数组) 使用变量对酒店进行循环/查房
print pol,hotel[pol] :
pol 得到-房间的号码
hotel[pol] 哪个酒店的哪个房间
[root@znix files]# awk 'BEGIN{hotel[110]="lidao" ;hotel[119]="tanjiaoshou";hotel[121]="taojin"
> for(pol in hotel)
> print pol,hotel[pol]
> }'
110 lidao
121 taojin
119 tanjiaoshou
3.3 【企业面试题】统计域名访问次数(去重统计)。处理以下文件内容,将域名取出并根据域名进行计数排序处理:(百度和sohu面试题)
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
3.3.1 方法一:sort uniq
uniq 命令 把相邻两行一样的合并
[root@znix ~]# awk -F '[/]+' '{print $2}' www.txt |uniq -c
2 www.etiantian.org
1 post.etiantian.org
1 mp3.etiantian.org
1 www.etiantian.org
sort 排序,默认是按照字母的顺序
[root@znix ~]# awk -F '[/]+' '{print $2}' www.txt |sort
mp3.etiantian.org
post.etiantian.org
www.etiantian.org
www.etiantian.org
www.etiantian.org
3.3.2 方法2 awk数组
3.3.2.1 第一步 取出域名
[root@znix ~]# awk -F '[/]+' '{print $2}' www.txt
www.etiantian.org
www.etiantian.org
post.etiantian.org
mp3.etiantian.org
www.etiantian.org
3.3.2.2 第二步 显示
; 两条命令之间用分号分割。
[root@znix ~]# awk -F '/+' '{hotel[$2]++;print hotel["www.etiantian.org"]}' www.txt
1
2
2
2
3
3.3.2.3 第三步 显示结果
[root@znix ~]# awk -F '/+' '{hotel[$2]++}END{for(pol in hotel)print pol,hotel[pol]}' www.txt
mp3.etiantian.org 1
post.etiantian.org 1
www.etiantian.org 3
第4章 课后题目:
两个文件 secure.zip access.zip
4.1 统计secure文件中谁在破解你的密码(统计出破解你密码的ip地址出现的次数)
4.1.1 方法一
[root@znix test]# awk '/Failed/{fa[$(NF-3)]++}END{for(pol in fa)print pol,fa[pol]}' secure-20161219|column -t
218.65.30.126 17163
218.65.30.61 17163
125.16.71.175 4
169.46.38.74 9
183.136.238.78 30
218.2.0.16 10
122.228.238.66 1
……
4.1.2 方法二
[root@znix test]# awk '/Failed/{print $(NF-3)}' secure-20161219 |sort|uniq -c|sort -n
4.1.3 结果统计
[root@znix test]# awk '/Failed/{fa[$(NF-3)]++}END{for(pol in fa)print pol,fa[pol]}' secure-20161219|column -t|wc -l
88
4.2 统计access.log文件中对ip地址去重并统计重复数
[root@znix test]# awk '{hotel[$1]++}END{for(pol in hotel)print pol,hotel[pol]}' access.log |head -3
101.226.125.115 284
180.154.137.177 516
101.226.125.116 127
4.3 统计access.log文件中网站一共使用了多少流量
[root@znix test]# awk '{i=i+$10}END{print i}' access.log
2478496663