文本处理——awk
awk工作原理和基本用法说明
-
awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK
-
有多种版本:
- AWK:原先来源于 AT & T 实验室的的AWK
- NAWK:New awk,AT & T 实验室的AWK的升级版
- GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容
-
GNU AWK 用户手册文档:https://www.gnu.org/software/gawk/manual/gawk.html
-
gawk:模式扫描和处理语言,可以实现以下功能
- 文本处理
- 输出格式化的文本报表
- 执行算数运算
- 执行字符串操作
-
命令格式:
awk [options] 'program' var=value awk [options] -f programfile file... var=value file... - 说明: program通常是被放在单引号中,并可以由三种部分组成 BEGIN语句块 模式匹配的通用语句块 END语句块 - 常见选项: -F “分隔符” 指明输入时用到的字段分隔符,默认的分隔符是若干个连续空白符 -v var=value 变量赋值 -
program格式:
pattern{action statements;..}pattern:决定动作语句何时触发及触发事件,比如:BEGIN,END,正则表达式等
action statements:对数据进行处理,放在{}内指明,常见:print, printf -
awk 工作过程
- 第一步:执行BEGIN{action;... }语句块中的语句
- 第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;... }语句块,它逐行扫描文件, 从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
- 第三步:当读至输入流末尾时,执行END{action;...}语句块
- BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中
- END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块
- pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块
-
分隔符、域和记录
- 由分隔符分隔的字段(列column, 域field)标记$1,$2...$n称为域标识,$0为所有域, 注意: 和shell中变量$符含义不同
- 文件的每一行称为记录record如果省略action, 则默认执行 print $0 的操作
-
常用的action分类:
- output statements:print,printf
- Expressions:算术,比较表达式等
- Compound statements:组合语句
- Control statements:if, while等
- input statements
-
awk控制语句:
- { statements;... } 组合语句
- if(condition)
- if(condition) {statements;...} else
- while(conditon)
- do {statements;...} while(condition)
- for(expr1;expr2;expr3)
- break
- continue
- exit
动作 print
格式:
print item1, item2, ...
说明:
- 逗号分隔符
- 输出item可以字符串,也可是数值;当前记录的字段、变量或awk的表达式
- 如省略item,相当于print $0
- 固定字符符需要用“ ” 引起来,而变量和数字不需要
范例:
[root@centos7 ~]# awk '{print "hello,awk"}' #没有标准输入,不会执行打印动作
^C
[root@centos7 ~]# seq 3 | awk '{print "hello,awk"}' #从管道接受到三个输入,执行三次打印动作
hello,awk
hello,awk
hello,awk
[root@centos8 ~]#awk -F: '{print $0}' /etc/passwd #逐行读取并打印文件内容
[root@centos8 ~]#awk -F: '{print $1,$3}' /etc/passwd #以:作为分隔符,打印1,3列的数据(默认以空格分割打印结果)
[root@centos8 ~]#awk -F: '{print $1"\t"$3}' /etc/passwd #以:作为分隔符,打印1,3列的数据(以\t分割打印结果)
#查看系统的文件系统挂载情况
[root@centos8 ~]#grep "^UUID" /etc/fstab |awk {'print $2,$3'}
/ xfs
/boot ext4
/data xfs
swap swap
范例:取出网站访问量最大的前3个IP
[root@VM_0_10_centos logs]# awk '{print $1}' /va/log/nginx/access.log |sort | uniq -c |sort -nr|head -3
5498 122.51.38.20
2161 117.157.173.214
953 211.159.177.120
#取前10个IP
[root@centos8 ~]#awk '{print $1}' /var/log/nginx/access.log |sort |uniq -c|sort -nr|head
4870 172.20.116.228
3429 172.20.116.208
2834 172.20.0.222
2613 172.20.112.14
2267 172.20.0.227
2262 172.20.116.179
2259 172.20.65.65
1565 172.20.0.76
1482 172.20.0.200
1110 172.20.28.145
范例:取出分区利用率
[root@centos7 ~]# df | awk '{print $1,$5}'
文件系统 已用%
devtmpfs 0%
tmpfs 1%
tmpfs 1%
tmpfs 0%
/dev/vda1 8%
tmpfs 0%
#使用扩展正则
[root@centos7 ~]# df | awk -F"[[:space:]]+|%" '{print $1,$5}'
文件系统 已用
devtmpfs 0
tmpfs 1
tmpfs 1
tmpfs 0
/dev/vda1 8
tmpfs 0
[root@centos7 ~]# df | awk -F"[ ]+" '{print $1,$5}'
文件系统 已用%
devtmpfs 0%
tmpfs 1%
tmpfs 1%
tmpfs 0%
/dev/vda1 8%
tmpfs 0%
#配合sed
[root@centos7 ~]# df | sed '1d' | awk -F"[ ]+" '{print $1,$5}'
devtmpfs 0%
tmpfs 1%
tmpfs 1%
tmpfs 0%
/dev/vda1 8%
tmpfs 0%
范例:取得系统的IP地址
[root@centos7 ~]# hostname -I | cat -A #hostname -I 的输出结果后有一个空格
10.0.24.17 172.17.0.1 $
[root@centos7 ~]# hostname -I | awk '{print $1,$2}'
10.0.24.17 172.17.0.1
[root@centos7 ~]# ifconfig eth0 | sed -n '2p' | awk '{print $2}'
10.0.24.17
范例:现有文件host_list.log,取“.magedu.com”前面的主机名部分追加到原文件
[root@centos7 ~]# cat host_list.log
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
[root@centos7 ~]# awk -F"[ .]" '{print $2}' host_list.log >> host_list.log
[root@centos7 ~]# cat host_list.log
1 www.magedu.com
2 blog.magedu.com
3 study.magedu.com
4 linux.magedu.com
5 python.magedu.com
www
blog
study
linux
python
awk变量
awk中的变量分为:内置变量和自定义变量
常见内置变量:
-
FS:输入字段分隔符(默认为空白字符),功能相当于-F
范例:#使用内置变量(-v 表示定义变量) [root@centos7 ~]# awk -v FS=":" '{print $1,$3}' /etc/passwd | head -3 root 0 bin 1 daemon 2 [root@centos7 ~]# awk -v FS=":" '{print $1,FS,$3}' /etc/passwd | head -3 root : 0 bin : 1 daemon : 2 [root@centos7 ~]# awk -F: '{print $1,$3}' /etc/passwd | head -3 root 0 bin 1 daemon 2 #使用自定义变量 [root@centos8 ~]#S=: ; awk -F$S '{print $1,$3}' /etc/passwd|head -3 root 0 bin 1 daemon 2 # -F 和 FS 功能是相同的,同时使用时 -F优先级高 [root@centos7 ~]# awk -v FS=":" -F";" '{print $1}' /etc/passwd |head -3 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin [root@centos7 ~]# awk -v FS=";" -F":" '{print $1}' /etc/passwd |head -3 root bin daemon -
OFS:输出字段分隔符,默认为空白字符
范例:#默认输出字段分隔符为空格 [root@centos7 ~]# awk -F: '{print $1,$3,$7}' /etc/passwd | head -1 root 0 /bin/bash #定义输出字段分隔符为@ [root@centos7 ~]# awk -F: -v OFS='@' '{print $1,$3,$7}' /etc/passwd | head -1 root@0@/bin/bash -
NF:字段数量——按OFS后分割的文件的每一行的字段数量,也即是有多少列
[root@centos7 ~]# awk -F: '{print NF}' /etc/passwd |head -3 7 7 7 [root@centos7 ~]# awk -F: '{print NF}' /etc/fstab | head -3 0 1 1
范例:获取与本机建立连接数最多的前3个IP
[root@centos7 ~]# ss -nt | awk -F'[ ]+|:' '/^ESTAB/{print $(NF-2)}' | sort | uniq -c | head -3 1 101.204.31.242 1 169.254.0.138 1 169.254.0.55
范例:每十分钟一次,将与本机建立连接数超过100个以上的IP放入黑名单,禁止其访问本机的服务(防止DDoS攻击)
<details>
<summary>点击查看代码</summary>
```
[root@centos8 ~]#cat deny_dos.sh
LINK=100
while true;do
ss -nt | awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'|sort |uniq -c|while read
count ip;do
if [ $count -gt $LINK ];then
iptables -A INPUT -s $ip -j REJECT
fi
done
done
[root@centos8 ~]#chmod +x /root/deny_dos.sh
[root@centos8 ~]#crontab -e
[root@centos8 ~]#crontab -l
*/10 * * * * /root/deny_dos.sh
```
</details>
- NR:记录的编号(行号)
范例:[root@centos7 ~]# awk '{print NR,$0}' /etc/passwd | head -3 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
范例:取ifconfig输出结果中的IP地址
[root@centos7 ~]# ifconfig eth0 | awk 'NR==2{print $2}' 10.0.24.17
范例:统计文件行数
[root@centos7 ~]# cat /etc/passwd | wc -l 33 [root@centos7 ~]# cat /etc/passwd |awk 'END{print NR}' 33
-
FNR: 分别打印文件的记录数——不要合并计数
范例:1 \S 2 Kernel \r on an \m 3 4 CentOS Linux release 7.9.2009 (Core) [root@centos7 ~]# awk '{print FNR,$0}' /etc/issue /etc/redhat-release 1 \S 2 Kernel \r on an \m 3 1 CentOS Linux release 7.9.2009 (Core) -
FILENAME: 当前文件名
范例:[root@centos7 ~]# awk 'END{print FILENAME}' /etc/fstab /etc/fstab -
ARGC: 命令行参数的个数
范例:#三个参数分别为 awk /etc/issue /etc/redhat-release [root@centos7 ~]# awk 'BEGIN{print ARGC}' /etc/issue /etc/redhat-release 3 -
ARGV: 命令行参数数组
范例:[root@centos8 ~]#awk 'BEGIN{print ARGV[0]}' /etc/issue /etc/redhat-release awk [root@centos8 ~]#awk 'BEGIN{print ARGV[1]}' /etc/issue /etc/redhat-release /etc/issue [root@centos8 ~]#awk 'BEGIN{print ARGV[2]}' /etc/issue /etc/redhat-release /etc/redhat-release [root@centos8 ~]#awk 'BEGIN{print ARGV[3]}' /etc/issue /etc/redhat-release -
自定义变量
自定义变量是区分字符大小写的,使用下面方式进行赋值 -
-v var=value
-
在program中直接定义
范例:[root@centos8 ~]#awk -v test1=test2="hello,gawk" 'BEGIN{print test1,test2}' test2=hello,gawk [root@centos8 ~]#awk -v test1=test2="hello1,gawk" 'BEGIN{test1=test2="hello2,gawk";print test1,test2}' hello2,gawk hello2,gawk [root@centos7 ~]# awk -v test="hello gawk" 'BEGIN{print test}' /etc/fstab hello gawk [root@centos7 ~]# awk 'BEGIN{test="hello,gawk"; print test}' hello,gawk #程序中定义 [root@centos7 ~]# cat awkscript {print script,$1,$2} [root@centos7 ~]# awk -F: -f awkscript script="awk" /etc/passwd | head -3 awk root x awk bin x awk daemon x

浙公网安备 33010602011771号