Linux之awk的进阶使用

系列文章目录

第一章 正则表达式,一张表教你学会
第二章 Linux之awk的进阶使用
第三章 Linux之sed命令的基本使用
第四章 Linux之grep、egrep命令(文本三剑客完)



awk是一门编程语言,用于语言处理,用于对文本进行截取效果好,在对一些文本进行分类统计时也很方便

格式: awk [选项] ‘BEGIN{}pattern{}END{}’ 文件

BEGIN和END只在开始和结尾时执行一遍,pattern则对匹配的行都分别执行一遍

[root@localhost 74]# awk -F:  'BEGIN{print "###start@@@@"} $3>500&&$3<2000{print $1,$3} END{print "###end####"}' /etc/passwd	# 得到第三字段大于500且小于2000的行的第1和第3字段
###start@@@@
polkitd 999
chrony 998
daifurong 1001
wujiaxi 1010
###end####

操作符

数学运算:+,-,*,/,%,++,–

逻辑关系符:&&,||,! -->&&比||的优先级要高

比较运算符:>,<,>=,!=,<=,==,,! -->==为文本数据表达式(精确匹配), ~表示匹配后面的模式(模糊匹配)


关键

$0 :为整行 $1为第1个字段 $n为第n个字段

num=0 :定义变量

NR :行号 --number of record

NF :字段数 --number of field

length() :得到字符串长度,内置函数

" ; " :命令分隔符

/正则/ :pattern中使用正则的格式,需要使用/ /包围,匹配符合正则的行

OFS :OFS在pattern中使用,用于指定输出时的字段分隔符,默认为一个空格,还有其他pattern时用()包围 --output field separater

ORS :输出时的行分割符,默认为换行,用法同上,ORS和OFS也可以在BEGIN中定义

FS :输入时的字段分隔符,默认空白,用法同上,也可以用-F选项指定


选项

-F 指定输入时的分隔符,用于分隔字段,默认为空白,可以指定多个,如-F “[:;]”,表示 : 和 ; 都可以作为分隔符, -F[:;] 或者 -F’[:;]’ 的写法都行

​ -F 实际上赋的值是一个正则表达式,当以多个空格和 : 分隔时也可以这样使用-F “[ :]+”

-v 定义变量,可以提前将其他变量赋值给awk内部变量,当然变量也会保留到shell中

[root@localhost ~]# name="ly"
[root@localhost ~]# awk -v user=$name '{print user}' /etc/passwd	# 变量不可用于正则中
ly
ly
……

​ 当然也不一定要使用-v,当要使用系统变量的时候,也可以使用双引号,不过awk命令中的其它不是引用变量的 $ 符前面都要加 \

[root@localhost ~]# echo "hello,ly" | awk "/$name/{print \$0}"		# 变量不可用于{}中
hello,ly

内置函数

length()返回字符串长度

例:查看没设密码的用户

[root@localhost ~]# awk -F: 'length($2)<=2{print $1,++sum}END{print sum}' /etc/shadow
bin 1
daemon 2
……
tcpdump 24
24

substr()返回指定字符串的指定部分

substr(目标字符串,起始下标,截取长度)

例:截取用户名的前两个字符,最后输出用户个数

[root@localhost lianxi]# awk -F: 'length($2)<=2 {print substr($1,1,2);sum++}END{print sum}'  /etc/shadow
bi
da
……
tc
24

system()执行shell命令

例:根据文件批量创建用户,批量删除用户

[root@localhost 225]# cat list
xw1 123
xw2 234
xw3 345
[root@localhost 225]# awk '{system("useradd "$1)}' list		# useradd后面的空格也要括起来
[root@localhost 225]# ls /home
changde  temp  xw1  xw2  xw3  
[root@localhost 225]# awk '{system("userdel -r "$1)}' list
[root@localhost 225]# ls /home
changde  temp  

split()切片

split(字符串,存放切片后数据的数组名,分割符)

例:通过ip add得到IP地址并去除子网掩码

[root@localhost 225]# ip address|awk '/inet.*ens[0-9]+$/{split($2,ip,"/")}END{for (i in ip) print i,ip[i]}'
1 192.168.10.129	# 数组下标从1开始
2 24	# 子网掩码

toupper()、tolower()转大写小写

例:显示所有用户的大写用户名

[root@localhost 225]# awk -F: '{print toupper($1)}' /etc/passwd
ROOT
BIN
DAEMON
……

例题

例1:在passwd文件中找出用户名包含feng的记录

awk -F: '/feng/' /etc/passwd

例2:统计用户uid大于1000并且shell是使用bash的用户的数量

[root@localhost ~]# awk -F: 'BEGIN{num=0}$3>1000&&/bash$/{print $0;num++}END{print num}' /etc/passwd
sc3:x:1001:1001::/home/sc3:/bin/bash
sc1:x:1002:1002::/home/sc1:/bin/bash
ly:x:1003:1003::/home/ly:/bin/bash
yangmi:x:1004:1004::/home/yangmi:/bin/bash
yalin:x:1005:1005::/home/yalin:/bin/bash
zhangcz:x:7790:1006:sanchuang student:/home/zhuhai:/bin/bash
6

例3:输出第5行

[root@localhost 75]# awk 'NR==5{print NR,$0}' /etc/passwd
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

例4:输出5~10行

[root@localhost 75]# awk -F: 'NR>=5&&NR<=10{print NR,$3,$5}' /etc/passwd
5 4 lp
6 5 sync
7 6 shutdown
8 7 halt
9 8 mail
10 11 operator

习题

1.只显示df -h结果的第一列文件系统

df -h|awk '{print $1}'

2.显示passwd文件的第5行和第10行的行号和用户名

awk -F: 'NR=\=5||NR=\=10{print NR,$1}' /etc/passwd

3.使用NF变量显示passwd文件倒数第二列的内容

awk -F: '{print $(NF-1)}' /etc/passwd

4.显示passwd文件中第5到第10行的用户名

awk -F: 'NR>=5&&NR<=10{print $1}' /etc/passwd

5.显示passwd文件中第7列不是bash的用户名

awk -F: '$7!~/bash/{print $1}' /etc/passwd

6.显示passwd文件中行号是5结尾的行号和整行内容

awk -F: 'NR~/5$/{print NR,$0}' /etc/passwd

7.用ifconfig/ip add 只显示ip

ip add |awk '/ens33$/{print $2}'
yum  install net-tools  -y # 安装ifconfig命令的软件
ifconfig | awk 'NR=\=2{print $2}'

8.ifconfig 命令后使用awk显示ens33的入站流量和出站流量(字节)

ifconfig | awk 'NR=\=5||NR=\=7{print $5}'

9.使用awk命令统计以r开头的用户数目

awk 'BEGIN{sum=0}/^h/{print $1;sum++}END{print sum}' /etc/passwd

10.显示每隔2秒的流量的变化

watch -n 2 -d "ifconfig|awk 'NR=\=5||NR==7{print $5}'"

案例:统计每分钟流量

1.算出2022年7月份里的每一个分钟的流量,具体日志文件格式如下: 
[root@localhost 75]# cat test.txt
	2022-7-1 00:01:01 78
	2022-7-1 00:01:04 89
	2022-7-1 00:03:01 178
	2022-7-1 00:03:05 890
	2022-7-2 00:03:01 178
	2022-7-3 00:03:05 890
	2022-7-30 00:03:01 178
	2022-7-31 00:07:05 8900
[root@localhost 75]# awk '{time[$1,substr($1,5,1),substr($2,1,5)]+=$3}END{for (i in time)print i,time[i]}'  test.txt |sort -n -k 3 -t -		# 此为妙手,但是没有用正则过滤,需要文件本身格式准确
2022-7-1-00:01 167
2022-7-1-00:03 1068
2022-7-2-00:03 178
2022-7-3-00:03 890
2022-7-30-00:03 178
2022-7-31-00:07 8900
#  简单阐述一下本手思路:通过三层for循环遍历出7月所有日期小时分钟,然后过滤出每分钟里有流量的秒,最后进行累加得到每分钟的流量

妙手中涉及到了awk字典、for循环

流控与数组

awk-if

if(condition) statement1;else if(condition) statement2;else statement3

if(condition) {命令1;命令2}else if(condition) {命令1;命令2}else {statement3}

例:找出超级用户,系统用户,普通用户的个数

[root@localhost ~]# awk -F: 'BEGIN{s=0;x=0;u=0} {if($3==0) s++;if($3>=1&&$3<1000) x++;else u++} END{print s,x,u}' /etc/passwd		# 单条命令推荐格式
1 20 9
[root@localhost ~]# awk -F: 'BEGIN{s=0;x=0;u=0} {if($3==0){s++} else if($3>=1&&$3<1000){x++} else{u++}} END{print s,x,u}' /etc/passwd		# 多条命令推荐格式
1 20 9
[root@localhost ~]# awk -F: 'BEGIN{s=0;x=0;u=0} {if($3==0){s++;print $1"超级用户"} else if($3>=1&&$3<1000){x++;print $1"系统用户"} else{u++;print $1"普通用户"}} END{print "超级用户:"s,"系统用户:"x,"普通用户:"u}' /etc/passwd
root超级用户
bin系统用户
daemon系统用户
……
huangtao普通用户
zhangcz普通用户
tcpdump系统用户
超级用户:1 系统用户:20 普通用户:9

awk-for

awk的for循环格式
for (i=0;i<10;i++) print $i
for (i in array) {print array[i];print i}
# 单命令可以不用{},多命令在{}中用;分隔

[root@xiaowei 20220705]# echo 1 2 3 4 5 6|awk '{for(i=1;i<=NF;i++) sum+=i;print sum}'
21

awk-数组(字典)

数组名[key]=value,key可以由多个字符串拼接而成,用逗号分隔,例:uesr[1,2,3]=3,则user[123]=3

[root@localhost lianxi]# awk -F: '{user[$1]=$3} END{for (i in user) print user[i]}' /etc/passwd
7789
72
……
1000
4

例:得到日志中的ip和该ip累计下载的文件大小,根据文件大小降序排列得到前100个ip,假设文件大小在第10个字段

awk '{ip[$1]+=$10}END{for (i in ip) print i,ip[i]}'|sort -k 2 -n -r | head -100

案例

有如下nginx_log日志,解答下面两个问题

以下是nginx日志的字段含义
$time_iso8601|$host|$http_cf_connecting_ip|$request|$status|$body_bytes_sent|$http_referer|$http_user_agent
-------------------------------------
2019-04-25T09:51:58+08:00|a.google.com|47.52.197.27|GET /v2/depth?symbol=aaa HTTP/1.1|200|24|-|apple
2019-04-25T09:52:58+08:00|b.google.com|47.75.159.123|GET /v2/depth?symbol=bbb HTTP/1.1|200|407|-|python-requests/2.20.0
2019-04-25T09:53:58+08:00|c.google.com|13.125.219.4|GET /v2/ticker?timestamp=1556157118&symbol=ccc HTTP/1.1|200|162|-|chrome
2019-04-25T09:54:58+08:00|d.shuzibi.co|-||HEAD /justfor.txt HTTP/1.0|200|0|-|-
2019-04-25T09:55:58+08:00|e.google.com|13.251.98.2|GET /v2/order_detail?apiKey=ddd HTTP/1.1|200|231|-|python-requests/2.18.4
2019-04-25T09:56:58+08:00|f.google.com|210.3.168.106|GET /v2/trade_detail?apiKey=eee HTTP/1.1|200|24|-|-
2019-04-25T09:57:58+08:00|g.google.com|47.75.115.217|GET /v2/depth?symbol=fff HTTP/1.1|200|397|-|python-requests/2.18.4
2019-04-25T09:58:58+08:00|h.google.com|47.75.58.56|GET /v2/depth?symbol=ggg HTTP/1.1|200|404|-|safari
2019-04-25T09:59:58+08:00|i.google.com|188.40.137.175|GET /v2/trade_detail?symbol=hhh HTTP/1.1|200|6644|-|-
2019-04-25T10:01:58+08:00|j.google.com|2600:3c01:0:0:f03c:91ff:fe60:49b8|GET /v2/myposition?apiKey=jjj HTTP/1.1|200|110|-|scan

1.计算每分钟的带宽(body_bytes_sent)

awk -F"|" '{time[substr($1,1,16)]+=$6} END{for (i in time) print i,time[i]}' nginx_log.txt
2019-04-25T10:01 110
2019-04-25T09:56 24
2019-04-25T09:57 397
2019-04-25T09:58 404
2019-04-25T09:59 6644
2019-04-25T09:51 24
2019-04-25T09:52 407
2019-04-25T09:53 162
2019-04-25T09:54 200
2019-04-25T09:55 231

2.统计每个URl(即去掉问号?后面的内容)的每分钟的频率

[root@localhost 223]# awk -F"[| ?]+" '{url[$5]++} END{for (i in url) print i,url[i]}' nginx_log.txt
/justfor.txt 1
/v2/myposition 1
/v2/depth 4
/v2/order_detail 1
/v2/trade_detail 2
/v2/ticker 1

总结

本章内容就到这里,因为markdown的格式问题,或许有一些有纰漏的地方,另外如有其他的错误都欢迎大家在评论区指出,我会在收到后第一时间改正,谢谢大家观看!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

只何

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值