shell法宝之awk,教你如何熟练掌握文件内容的输出和搜索

一、概述

原理

  • 逐行读取文本,默认是用空格键或 “ tab ” 键为分隔符进行分隔
  • 将分隔所得的各个字段都保存到内建变量中,并按模式或者条件执行编辑命令
  • 与sed编辑器类似

特点

  • sed命令通常用于一个整行的处理,awk则是倾向于将一整行分成多个“字段”,然后再进行处理

  • awk信息的读入是逐行读取的,执行结果可以通过 print 的功能将字段打印出来

  • 在使用awk命令的过程中,可以用逻辑操作符号表示以下功能

逻辑操作符代表
&&
丨丨
+
-
*
/
^取余和乘方

二、awk命令

2.1 格式

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

2.2 常见变量

变量名作用
FS列分割符,指定每行文本的字段分隔符,默认是空格或制表位,和 “-F” 一样
NE当前处理的行的字段个数
NR当前处理的行的行号(序数)
$0当前处理的行的整行内容
$n当前处理行的第n个字段(第n列)
FILENAME被处理的文件名
RS行分隔符,awk文件读取资料时,根据RS的定义来分割成多条记录,而awk一次仅读入一条记录,以进行处理,预设值是 “ \n ”

三、测试

3.1 简易文本输出测试

  • 输出全部内容
# 功能一样,$0单独使用时可不添加
awk '{print}' cc.txt
awk '{print $0}' cc.txt 

A
B
C
D
E
F
G
H
111
222
333
  • 输出范围行数
  • 共两种方式,功能一样
awk 'NR==1,NR==5 {print}' cc.txt 			# “==”表示等于,NR为当前行数

awk '(NR>=1)&&(NR<=5) {print}' cc.txt 		# >=,<= 同样代表一定范围行,中间需要使用&&连接
A
B
C
D
E
  • 输入指定行数
  • 使用||指定输出所需行数
awk 'NR==1||NR==5 {print}' cc.txt 		# ||表示或
A
E
  • 输出奇偶行
  • 当前行取余等于1则是奇数,0则是偶数
awk '(NR%2)==1 {print}' cc.txt 			# 奇数行
A
C
E
G
111
333

awk '(NR%2)==0 {print}' cc.txt 			# 偶数行
B
D
F
H
222
  • 输出需求开头或者结尾的行
  • 与sed一样,^代表开头,$代表结尾
awk '/^4/ {print}' cc.txt 			# 4开头的行
4D
awk '/Z$/ {print}' cc.txt 			# Z结尾的行
111Z

3.2 BEGIN

BEGIN 模式表示,在处理指定的文本之前,需要先执行此模式中指定的动作, awk 在处理指定的文本,之后再执行 END 模式中指定的动作,END{ } 语句中,一般都会放打印结果等语句

举列

  • 筛选出passwd文件内已 /bin/bash 结尾的行数
  • \表示转义,否则 /bin 无法查找到
awk 'BEGIN {x=0};/\/bin\/bash$/{x++};END {print x}' passwd 
16

3.3 输出特殊字段

  • 输出每行中第一个字段
  • 这里需要使用 -F 把文本内每行字段之间的 " : " 指定出来
awk -F ":" '{print $1}' passwd 		# 打印第一个字段
root
bin
daemon
adm
lp
sync
shutdown
halt
  • 输出每行的第1和第3字段
  • 和前面一样,加个 $3 即可
awk -F ":" '{print $1,$3}' passwd 			# 默认输出出来的都是以空格做分隔
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
  • 基于上面例题,再增加一条要求第三段数值小于10的行
awk -F ":" '$3<10{print $1,$3}' passwd 			# 添加个$3<10即可
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
  • 再做改进,单独输出第三段数值大于1000的行
  • 大于也就是不小于,使用!
  • BEGIN命令也可使用,先处理BEGIN,再处理后面的
awk -F ":" '!($3<1000){print $3}' passwd		# 使用!别忘了用()将内容合并一起
65534
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014

awk 'BEGIN {FS=":"};{if($3>=1000){print}}' passwd 		# 此命令也可以
  • 给每行添加序号
awk -F ":" '{print NR,$0}' passwd 		# 每处理完一条,NR值加1
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
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
...
57 ccaadd:x:1014:1014::/home/ccaadd:/bin/bash
  • 输出 /bash 结尾行的第一段内容
awk -F ":" '$7~"/bash"{print $1}' passwd 		# 先搜索/bash结尾的行,然后打印出第一段
root
dcc
123456
ccd
ddccdd
dccccccc
ccccc
ccaa
ccaacc
dcc666
ccaz
ssassa
33333
1212313
465456465
ccaadd
  • 输出第一段是root开头,而且还需要共七段,并且只输出其中的第1.2段
awk -F ":" '($1~"root")&&(NF==7){print $1,$2}' passwd  		# 按照顺序搜索
root x
  • 输出第七段不是/bin/bash 也不是 /sbin/nologin 的行
awk -F ":" '!($7!="/bin/bash")&&($7!="/sbin/nologin"){print}' passwd 	# 两个选项放一起使用&&
root:x:0:0:root:/root:/bin/bash
dcc:x:1000:1000:dcc:/home/dcc:/bin/bash
123456:x:1001:1001::/home/123456:/bin/bash
ccd:x:1002:1002::/home/ccd:/bin/bash
ddccdd:x:1003:1003::/home/ddccdd:/bin/bash
...

三元运算符使用

  • 例图
    在这里插入图片描述
  • 需求
    • 要求输出这两列中字符大的数值
    • 如果第三个字段的值大于第四个字段,则把第三字段值赋给max,反之则把第四段值赋给max
awk -F ":" '{max=($3>=$4)?$3:$4;{print max}}' passwd
0
1
2
4
7
5
6
7
12
11

3.4 配合shell命令使用

  • 统计PATH中,以 “ : ” 分隔的段落数
echo $PATH | awk 'BEGIN{RS=":"};END{print NR}'		# END最后最后执行
5
  • 统计 bash 用户的个数
  • 配合管道符合,使用 wc -l 命令
awk -F ":" '/bash$/{print | "wc -l"}' passwd 
16
  • 查看系统内存使用比
  • free -m查看系统内存
  • 搜索出Mem这一行,然后使用第三段除以第三+四段(总内存)
  • 乘100加上% 更直观
free -m | awk '/Mem:/ {print int($3/($3+$4)*100)"%"}'
22%
  • 查看CPU的空闲率
  • top -b -n 1 查看本机进程信息
  • 使用 grep 搜索出 cpu 这一行
  • $4 晒出第四段
  • $1 输出第一段,并且加上一个% 直观些
top -b -n 1 | grep Cpu | awk -F "," '{print $4}' | awk '{print $1"%"}'
100.0%
  • 显示上次系统重启的时间
  • second ago 表示显示多少秒前的时间
  • %F %H:%M:%S 表示时间格式,年月日秒
date -d "$(awk -F "." '{print $1}' /proc/uptime) second ago" +"%F %H:%M:%S"
2021-05-17 02:48:29

3.5 getline

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

举列

  • seq 10 输出的是1-10行
  • 先由awk获取第一行,然后getline获取第二行,反复进行后,得到的结果如下
seq 10 | awk '{getline;print $0}'
2
4
6
8
10
  • 反过来则是,print $0先读取了awk读取的第一行
  • getline读取2,但是不打印,反复循环,结果如下
seq 10 | awk '{print $0;getline}'
1
3
5
7
9

3.6 OFS

OFS:输出的分隔符

举列

  • OFS表示输出的分隔符为 “ | ”
  • $1=$1 用来激活$0的赋值
  • 通常会在改变OFS后面需要输出$0时才要求重新激活
echo "A B C D" | awk '{OFS="|";print $0;$1=$1;print $0}'
A B C D
A|B|C|D

3.7 awk与数组

  • 设置下标0 1的值,打印出对应结果
awk 'BEGIN{a[0]=10;a[1]=20; print a[1]}'		# 输出下标1
20
awk 'BEGIN{a[0]=10;a[1]=20; print a[0]}'		# 输出下标2
10
  • 同样设置,将下标改为英文字母
awk 'BEGIN{a["abc"]=10;a["def"]=20; print a["abc"]}'		# 英文字母需要使用 “”
10
awk 'BEGIN{a["abc"]=10;a["def"]=20; print a["def"]}'
20
  • 设置循环打印
awk 'BEGIN{a[0]=10;a[1]=20;a[2]=30;for(i in a){print i,a[i]}}'
0 10
1 20
2 30

BEGIN中的命令只能执行一次
awk数组的下标除了数字还可以使用字符串,不过字符串需要 “”

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值