文本处理——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
    
posted @ 2022-04-22 17:00  浅笑人伤  阅读(74)  评论(0)    收藏  举报