我们将/etc/passwd/文件拷贝到/data/下做实验,以免影响系统
过滤、统计、计算、过滤统计日志
1.逐行读取文本,默认以空格或tab键为分隔符进行分割,将分割所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令;
2.sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个"字段"在进行处理
3.awk信息读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示
4.在使用awk命令的过程中,可以使用逻辑操作符“&&”表示与、“||”表示或、”!“表示非,还可以进行简单的数字运算如±*/%^,分别表示加减乘除取余和乘方
awk 选项 ‘模式或条件{操作}’ 文件1 文件按2
awk -f 脚本文件 文件1 文件2......
名词 | awk中的叫法 | 一些说明 |
---|---|---|
行 | 记录record | 每一行默认通过回车分割的 |
列 | 字段,域field | 每一列默认通过空格分隔的 |
注意:awk中默认的东西都是可以修改的
awk | |
---|---|
NR==1 | 取出某一行 |
NR>=1&&NR<=5 | 取出1-5行范围 |
$0 | 整行 |
/old/ | 过滤 |
/100/,/110/ | 100到110行 |
符号 | <> >= <= == != |
[root@test1 data]# awk 'NR==1' user.txt
1,zhangsan #取第一行
[root@test1 data]# awk 'NR>=1 && NR<=3' user.txt
1,zhangsan #取一到三行 中间空格可加可不加
2,lisi
3,wangwu
[root@test1 data]# ll |awk 'NR==2'
-rw-r--r-- 1 root root 29 12月 3 18:24 config
[root@test1 data]# ll |awk 'NR==2{print $0}'
-rw-r--r-- 1 root root 29 12月 3 18:24 config
#两种写法的效果一样
-F 指定分隔符,指定每一列结束标记(默认是空格,连续的空格,tab键)
$ 数字 列出某一列;注意:在awk 中$内容就一个意思,表示取出某一列
column -t 文本对齐
$NF 表示最后一列
[root@test1 data]# ll |awk '{print $5}'
#必须要加花括号$加数字,就是取那一列
29
31
1306
1306
47
[root@test1 data]# ll |awk '{print $5,$9}'
#取出查看文件的大小和文件名,但是有点乱
29 config
31 ip.txt
1306 passwd
1306 test
47 user.txt
[root@test1 data]# ll |awk '{print $5,$9}' |column -t
#使用管道传给column -t对齐显示
29 config
31 ip.txt
1306 passwd
1306 test
47 user.txt
[root@test1 data]# ll |awk '{print $5,$NF}' | column -t
$NF表示最后一列,当我们要取的列很多不知道最后一列时可以使用
29 config
31 ip.txt
1306 passwd
1306 test
47 user.txt
取出passwd的第一列和最后一列
[root@test1 data]# awk -F: '{print $1,$NF}' passwd |column -t
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
lp /sbin/nologin
sync /bin/sync
#将passwd第一列和最后一列交换,只需要$1和$NF
[root@test1 data]# awk -F: '{print $NF,$1}' passwd
/bin/bash root
/sbin/nologin bin
/sbin/nologin daemon
/sbin/nologin adm
/sbin/nologin lp
行与列名称
awk取行与取列
取出网卡IP地址(同时取行取列)
#取出IP地址
[root@test1 ~]# ifconfig
ens160: flags=4163 mtu 1500
inet 10.1.1.28 netmask 255.255.255.0 broadcast 10.1.1.255
inet6 fe80::20c:29ff:fe23:2b1f prefixlen 64 scopeid 0x20
[root@test1 ~]# ifconfig |awk 'NR==2' |awk -F"[ ]+" '{print $3}'
10.1.1.28 #("[ ]+"分隔符为空格,可能连续加上加号 $3第三列)
[root@test1 ~]# ifconfig |awk -F"[ ]+" 'NR==2{print $3}'
10.1.1.28 #('NR==2{print $3}'作为条件合并到一起)
FS | 列分隔符,指定每行文本的字段分隔符,默认为空格或者制表符,与-F作用相同 |
---|---|
OFS | 删除字段分割符(awk显示每一行的时候,每一列之间通过什么分割,默认空格) |
NF | 当前处理的行的字段个数 |
NR | 当前处理行的行号(序数) |
$0 | 当前处理的行的整行内容 |
$n | 当前处理行的第n个字段(第n列) |
FILENAME | 被处理的文件名 |
RS | 行分割符,预设值是‘\n’ |
命令 | 选项 | 条件{动作} |
---|---|---|
awk | -F"[ ]+" | ‘NR==2{print $3}’ |
比较符号:>< >= <= == !=
正则
范围表达式
特殊条件:BEGIN和END
//支持扩展正则
可以精确到某一列中是否包含改内容(sed和grep比较难实现)
~包含
!~不包含
正则 | awk正则 |
---|---|
^表示以……开头的行 | 某一列的开头 $3~/^root/ |
$表示以……结尾的行 | 某一列的结尾 3 / r o o t 3~/root 3 /root/ |
^$表示空行 | 某一列是空的,很少用 |
#第三列以2开头的行
[root@test1 data]# awk -F: '$3 ~/^2/' passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
/哪里开始/,/哪里结束/常用
NF==1,NF==5 从第一行开始到第五行结束 类似于sed -n '1,5p'
#显示指定时间(11:02到11:02:30)范围内容的IP地址
awk '/11:02:00/,/11:02:30/{print $1}' access.log
2.5.4特殊模式BEGIN{}和END{}
模式 | 含义 | 应用场景 |
---|---|---|
BEGIN{} | 里面的内容会在awk读取文件之前执行 | 统计、计算、不涉及读取文件 用来处理文件之前,添加表头 定义awk变量(也可以用-v) |
END{} | 里面的内容会在awk读取文件之后执行 | awk进行统计,一般过程:先进行计算,最后里面输出结果 awk使用数组,用来输出数组结果 |
常用统计方法:
统计方法 | 简写 | 应用场景 |
---|---|---|
i=i+1 | i++ | 计数 |
sum=sum+??? | sum+=??? | 求和累加 |
array[]=array[]+1 | array[]++ | 数组分类计数 |
#统计空行
[root@test1 data]# awk '/^$/{i++}END{print i}' test1
10
#求1加到100的和
[root@test1 data]# seq 100 |awk '{sum=sum+$1}END{print sum}'
5050
统计日志:统计每个IP出现次数;统计每种状态出现次数;统计系统中每个用户被攻击的次数;统计攻击者IP出现次数
累加求和:统计每个IP消耗的流量;
shell数组 | awk数组 | |
---|---|---|
形式 | array[0]=0 array[1]=1 | array[0]=0 array[1]=1 |
使用 | echo $array[0] $array[1] | print array[0] array[1] |
批量输出数组内容 | for i in ${array[*]} do echo $i done | for (i in array) print array[i] |
#awk数组案列
[root@test1 data]# awk 'BEGIN{a[0]=123456;a[1]="shixiao";print a[0],a[1]}'
123456 shixiao
[root@test1 data]# awk 'BEGIN{a[0]=123456;a[1]="shixiao";for(i in a)print a[i]}'
123456
shixiao
#上面是按需输出,下面是借助循环全部输出
[root@test1 data]# cat test1
http://www.shixiaohao.org/index.html
http://www.shixiaohoa.org/1.html
http://www.post.shixiaohao.org/index.html
http://mp3.shixiaohao.org/index.html
http://mp3.shixiaohao.org/index.html
http://post.shixiaohao.org/2.html
[root@test1 data]# awk -F"[/.]+" '{print $2}' test1
www
www
www
mp3
mp3
[root@test1 data]# awk -F"[/.]+" '{a[$2]++}END{for(i in a)print i,a[i]}' test1
www 3
mp3 2
post 1
[root@test1 data]# awk -F"[/.]+" '{a[$2]++}END{for(i in a)print i,a[i]}' test1|sort -rnk2
www 3
post 2
mp3 2
shell编程C语言for循环 | awk for 循环 | |
---|---|---|
for(i=1;i<=10;i++) do echo $i done | for (i=1;i<=10;i++) print i | awk for循环用来循环每个字段 |
[root@test1 data]# awk 'BEGIN{for(i=1;i<=100;i++)sum+=i;print sum}'
5050
shell if判断 | awk if判断 |
---|---|
if[i -eq 0];then echo " " fi | if(条件) print " " |
if[i -eq 0];then echo " " else echo " " fi | if(条件) print " " else print " " |
[root@test1 data]# df -h |awk -F"[ %]+" 'NR>1{if($5>10)print "disk not enough",$1}'
disk not enough /dev/sda1
注意:awk使用多个条件时,第一个条件可以放在‘条件{动作}’ 第二个条件 一般用if判断。