【Shell】文本三剑客-awk

目录

一、awk介绍

1.awk概述

2.awk的工作原理 

3.命令格式

4.awk常见的内建变量(可直接用)如下所示

二、按行输出文本

三、按字段输出文本

四、通过管道、双引号调用 Shell 命令

五、awk常用筛选数据实例


一、awk介绍

1.awk概述

AWK 是一种用于处理文本的编程语言工具。awk在很多方面类似于 shell 编程语言,尽管 awk具有完全属于其本身的语法。它的设计思想来源于 SNOBOL4 、sed 、Marc Rochkind设计的有效性语言、语言工具 yacc 和 lex ,当然还从 C 语言中获取了一些优秀的思想。在最初创造 awk 时,其目的是用于文本处理,并且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行

2.awk的工作原理 

逐行读取文本,默认以空格或tab键为分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令;
sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”再进行处理;
awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示;
在使用awk命令的过程中,可以使用逻辑操作符“&&”表示与、“||”表示或、“!”表示非,还可以进行简单的数学运算如+-*/%^,分别表示加减乘除取余和乘方

3.命令格式

awk 选项 '模式或条件 {操作}' 文件 1 文件 2 …
awk -f 脚本文件 文件 1 文件 2 …

4.awk常见的内建变量(可直接用)如下所示

变量含义
FS列分割符。指定每行文本的字段分隔符,默认为空格或制表位。与"-F"作用相同
NF当前处理的行的字段个数
NR当前处理的行的行号(序数)
$0当前处理的行的整行内容
$n当前处理行的第n个字段(第n列)
FILENAME被处理的文件名
RS行分隔符。awk从文件上读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录,以进行处理。预设值是'\n'

二、按行输出文本

awk '{print}' testfile2                 #输出所有内容
awk '{print $0}' testfile2                 #输出所有内容

awk 'NR==1,NR==3{print}' testfile2        #输出第 1~3 行内容
awk '(NR>=1)&&(NR<=3){print}' testfile2    #输出第 1~3 行内容

awk 'NR==1||NR==3{print}' testfile2        #输出第1行、第3行内容

awk '(NR%2)==1{print}' testfile2         #输出所有奇数行的内容
awk '(NR%2)==0{print}' testfile2        #输出所有偶数行的内容

awk '/^root/{print}' /etc/passwd        #输出以 root 开头的行

awk '/nologin$/{print}' /etc/passwd        #输出以 nologin 结尾的行

awk 'BEGIN {x=0};/\/bin\/bash$/{x++};END {print x}' /etc/passwd        #统计以/bin/bash 结尾的行数,等同于 grep -c "/bin/bash$" /etc/passwd

注意:BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作;awk再处理指定的文本,之后再执行END模式中指定的动作,END{}语句块中,往往会放入打印结果等语句

[root@localhost ~]# awk '{print}' testfile2
111
222
333
444
55555
666666
77

[root@localhost ~]# awk '{print $0}' testfile2
111
222
333
444
55555
666666
77

[root@localhost ~]# awk 'NR==1,NR==3{print}' testfile2
111
222
333

[root@localhost ~]# awk '(NR>=1)&&(NR<=3){print}' testfile2
111
222
333

[root@localhost ~]# awk 'NR==1||NR==3{print}' testfile2
111
333

[root@localhost ~]# awk '(NR%2)==1{print}' testfile2
111
333
55555
77

[root@localhost ~]# awk '(NR%2)==0{print}' testfile2
222
444
666666
[root@localhost ~]# 

[root@localhost ~]# awk '/^root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

三、按字段输出文本:

awk -F ":" '{print $3}' /etc/passwd         #输出每行中(以空格或制表位分隔)的第3个字段

awk -F ":" '{print $1,$3}' /etc/passwd        #输出每行中的第1、3个字段

awk -F ":" '$3<5{print $1,$3}' /etc/passwd    #输出第3个字段的值小于5的第1、3个字段内容

awk -F ":" '!($3<200){print}' /etc/passwd     #输出第3个字段的值不小于200的行

awk 'BEGIN {FS=":"};{if($3>=1000){print}}' /etc/passwd    #先处理完BEGIN的内容,再打印文本里面的内容

awk -F ":" '{max=($3>=$4)?$3:$4;{print max}}' /etc/passwd        #($3>$4)?$3:$4;三元运算符,如果第3个字段的值大于等于第4个字段的值,则把第3个字段的值赋给max,否则第4个字段的值赋给max

awk -F ":" '{print NR,$0}' /etc/passwd        #输出每行内容和行号,每处理完一条记录,NR值加1

awk -F ":" '$7~"/bash"{print $1}' /etc/passwd    #输出以冒号分隔且第7个字段中包含/bash的行的第1个字段

awk -F ":" '($1~"root")&&(NF==7){print $1,$2}' /etc/passwd    #输出第1个字段中包含root且有7个字段的行的第1、2个字段

awk -F ":" '($7!="/bin/bash")&&($7!="/sbin/nologin"){print}' /etc/passwd    #输出第7个字段既不为/bin/bash,也不为/sbin/nologin的所有行

四、通过管道、双引号调用 Shell 命令

echo $PATH | awk 'BEGIN{RS=":"};END{print NR}'        #统计以冒号分隔的文本段落数,END{}语句块中,往往会放入打印结果等语句

awk -F: '/bash$/{print | "wc -l"}' /etc/passwd        #调用 wc -l 命令统计使用 bash 的用户个数,等同于 grep -c "bash$" /etc/passwd

free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'    #查看当前内存使用百分比

top -b -n 1 | grep Cpu | awk -F ',' '{print $4}' | awk '{print $1}'        #查看当前CPU空闲率,(-b -n 1 表示只需要1次的输出结果)

date -d "$(awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H:%M:%S"        #显示上次系统重启时间,等同于uptime;second ago为显示多少秒前的时间,+"%F %H:%M:%S"等同于+"%Y-%m-%d %H:%M:%S"的时间格式
/proc/uptime 第一列输出的是,系统启动到现在的时间(以秒为单位);第二列输出的是,系统空闲的时间(以秒为单位)

date -d "$(date -d"1 month" +"%Y%m01") -3 day" +"%Y%m%d"  当月倒数第三天
date +"%Y%m01"        当月第一天

awk 'BEGIN {n=0 ; while ("w" | getline) n++ ; {print n-2}}'    #调用w命令,并用来统计在线用户数

awk 'BEGIN {"hostname" | getline ; {print $0}}'            #调用 hostname,并输出当前的主机名

seq 10 | awk '{getline; print $0}'      #获取偶数行
seq 10 | awk '{print $0; getline}'      #获取基数行

[root@localhost ~]# echo $PATH | awk 'BEGIN{RS=":"};END{print NR}'
5

[root@localhost ~]# awk -F: '/bash$/{print | "wc -l"}' /etc/passwd
6


[root@localhost ~]# free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'
16%


[root@localhost ~]# top -b -n 1 | grep Cpu | awk -F ',' '{print $4}' | awk '{print $1}'
94.3


[root@localhost ~]# date -d "$(awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H:%M:%S"
2024-05-18 01:16:43


[root@localhost ~]# awk 'BEGIN {"hostname" | getline ; {print $0}}'
localhost.localdomain


[root@localhost ~]# seq 10 | awk '{getline; print $0}'
2
4
6
8
10


[root@localhost ~]# seq 10 | awk '{print $0; getline}'
1
3
5
7
9
[root@localhost ~]#

注意:

当getline左右无重定向符“<”或“|”时,awk首先读取到了第一行,就是1,然后getline,就得到了1下面的第二行,就是2,因为getline之后,awk会改变对应的NF,NR,FNR和$0等内部变量,所以此时的$0的值就不再是1,而是2了,然后将它打印出来。
当getline左右有重定向符“<”或“|”时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。

FNR:awk当前读取的记录数,其变量值小于等于NR(比如当读取第二个文件时,FNR是从0开始重新计数,而NR不会)。
NR==FNR:用于在读取两个或两个以上的文件时,判断是不是在读取第一个文件

五、awk常用筛选数据实例

获取本机上一次开机时间
date -d "$(awk -F. '{print $1}' /proc/uptime) second ago" +"%Y%m%d %H:%M:%S"

[root@localhost ~]# date -d "$(awk -F. '{print $1}' /proc/uptime) second ago" +"%Y%m%d %H:%M:%S"
20240518 01:16:44

检测本机CPU最近15分钟的负载
uptime | awk '{print $NF}'

[root@localhost ~]# uptime | awk '{print $NF}'
0.05

查看CPU空闲率
top -b -n 1 | grep Cpu | awk -F ',' '{print $4}' | awk '{print $1}'  

[root@localhost ~]# top -b -n 1 | grep Cpu | awk -F ',' '{print $4}' | awk '{print $1}'
93.8

内存使用率

free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}' 

[root@localhost ~]# free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'
16%

磁盘分区容量使用率
df | grep -w "/" | awk '{print $5}' | awk -F% '{print $1"%"}' 

[root@localhost ~]# df | grep -w "/" | awk '{print $5}' | awk -F% '{print $1"%"}'
27%

检测入站网卡流量和出站网卡的流量
ifconfig ens33 | awk '/RX p/{print $5}'
ifconfig ens33 | awk '/TX p/{print $5}'

[root@localhost ~]# ifconfig ens33 | awk '/RX p/{print $5}'
1891937
[root@localhost ~]# ifconfig ens33 | awk '/TX p/{print $5}'
1626172

使用awk 统计 httpd 访问日志中每个客户端IP的出现次数?
# awk '{ip[$1]++}END{for(i in ip){print ip[i],i}' /var/log/httpd/access_log | sort -r
备注:定义数组,数组名称为ip,数字的下标为日志文件的第1列(也就是客户端的IР地址),++的目的在于对客户端进行统计计数,客户端IP出现一次计数器就加1。END中的指令在读取完文件后执行,通过循环将所有统计信息输出,for循环遍历的是数组名ip的下标。

使用 awk 去重
arr=(1 2 3 4 5 5 4 3 2 1)
awk -v RS=' ' '!a[$1]++' <<< ${arr[@]}
#-v 设置变量
#<<< 表示将后面的内容作为前面命令的标准输入
#awk '1' 就是 awk '1{print}' ,允许打印读入的行内容,例:echo 123 | awk '1'
#awk '0' 就是 awk '0{print}' ,不允许打印读入的行内容,例:echo 123 | awk '0'
#var++ 的形式:先读取 var 变量值,再对 var 值 +1
 awk 处理第一行时:先读取 a[$1] 值再自增,a[$1] 即 a[1] 值为空(即0),即为 awk '!0',即为 awk '1',即为 awk'1{print}'
 awk 处理第二行时:先读取 a[$1] 值再自增,a[$1] 即 a[1] 值为 1,即为 awk '!1',即为 awk '0',即为 awk '0{print}'

  • 40
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值