文章目录
前言
前文已详细了介绍了文本三剑客的其中两种grep 和 sed 命令,本文将介绍文本三剑客中的最后一种awk。
一.awk概念
AWK是一种用于文本处理和数据提取的工具。 它可以在命令行中使用,也可以作为脚本运行。 AWK通过处理文本流行来实现数据提取、格式化输出等功能 。
awk 还是一种编程语言环境,它提供了正则表达式的匹 配,流程控制,运算符,表达式,变量以及函数等一系列 的程序设计语言所具备的特性,它从C语言中获取了一些 优秀的思想
二.工作流程
- 第一步:自动从指定的数据文件中读取行文本。
- 第二步:自动更新awk的内置系统变量的值,例如列数变 量NF、行数变量NR、行变量 以及各个列变量1、$2等等
- 第三步:依次执行程序中所有的匹配模式及其操作
- 第四步:当执行完程序中所有的匹配模式及其操作之后, 如果数据文件中仍然还有为读取的数据行,则返回到第 (1)步,重复执行(1)~(4)的操作
三.awk执行方式
任何awk语句都由模式( pattern )和动作( action )组成
- 模式:由一组用于测试输入行是否需要执行动作的规则
- 动作:包含语句,函数和表达式的执行过程
- 简言之,模式决定动作何时触发事件,动作决定执行的处理动作
四.awk 语法结构及案例
语法结构:
纯命令执行脚本
awk 'pattern {action}' file#代表需要被执行的文件
#pattern是正文模式,用于筛选输入数据的行
#上述pattern是三种模式中的一种,剩余两种模式分别是begin和end模式
#action是执行动作,用于对符合特定条件的行执行某些操作
- begin模式:处理正文之前的准备工作都在此模式下执行
- end模式:正文处理结束退出之前的工作都在此模式下执行,简称收尾模式
- 例如:awk命令是执行依次正文内容输出一个结果,想要将正文全部处理结束之后一次性输出处理结果,则需要将输出工作放到end模式下
格式:
awk 'BEGIN{ commands } {print item1,item2,……} END{ commands }' [INPUTFILE…]
#begin 模式 命令用逗号隔开 输出以空格输出
参数:
- -F:指定分隔符
- -v:定义变量
- -f:从文件中读取awk脚本
- -F: '{print $2}':指定脚本
- -NR:输出指定范围的行
- -NF:输出当前行的字段数
- -OFS:指定输出分隔符
- -ORS:指定输出行分隔符
- -i:直接修改文件
案列 1:
[root@timeserver ~]# vim input
#输入多个回车制造多个空白行
[root@timeserver ~]# awk '/^$/{print "This is a blank line"}' input
This is a blank line
This is a blank line
This is a blank line
This is a blank line
#脚本调用流程为:模式条件/^$/检索空白行,匹配到一个空白行执行一个动作:print "This is a blank line
案例 2:
[root@server ~]# awk 'BEGIN{print "BEGIN ...."} {print $0} END{print "The End"}' /etc/fstab
# $0 代表这一行的所有列
上述命令执行流程:
#首先执行begin 模式打印一个抬头信息 ....
#接着执行pattern模式处理正文(print $0),读取正文第一行的所有列然后输出,
#第一行处理结束输出之后继续处理第二行输出,awk是按行顺序进行处理的
#最后执行end模式,进行最后的收尾工作
awk命令调用脚本执行
- 推荐模式和动作有多个时使用此方式执行
[root@server ~]# vim scr.awk
#编辑以下内容
/^$/{print "This is a blank line"}
#使用awk命令调用脚本执行
[root@server ~]# awk -f scr.awk input
This is a blank line
This is a blank line
This is a blank line
直接awk纯脚本执行
[root@server ~]# vim scr.awk
#首先编辑抬头申明脚本解释器
#!/bin/awk -f
/^$/{print "This is a blank line"}
#使用如下命令执行脚本
[root@server ~]chmod o+x scr.awk
[root@server ~]./scr.awk inout#被处理的文件名
五.记录和域
概念:
域:在awk中,域(field)是一行文本中的一个单独的数据项,通常由空格或制表符分隔。默认情况下,awk将输入行按照空格或制表符来划分域,默认为空格或tab。
记录:记录(record)是指awk处理的一行完整的输入文本。默认情况下,记录是以换行符为分隔符来定义的。在awk中,每个记录可以包含多个域,每个域可以通过域分隔符来分隔。$1表示第一个域 $0表示所有域 。
简尔言之:记录代表行,域代表列
案例1:处理每一行每一列
[root@timeserver ~]# awk '{print $0}' awk1.txt
#截取第一列为$1 第二列为$2
案例2:$之后的域使用变量定义
[root@server ~]# awk 'BEGIN{one=1 ; two=2} {print $(one+two)}' awk1.txt
案例3:查询包含 l 的行显示第三列
[root@server ~]# awk '/^l/{print $3}' awk1.txt
案列4: 输出所有账户
[root@server ~]# awk -F ":" '{print $1}' /etc/passwd
- awk默认识别空格来识别列与列,特殊文件中没有空格及awk默认识别的分隔符
- 需要使用参数 -F 来指定分割符
六.awk的变量
$0: 记录变量表示所有域(列) $n 字段变量,表示第n个域(列)
NF: 当前记录的域个数
NR :显示每一行的行号
FS: 输入字段分隔符,默认值是空格或者制表 符,可使用-F指定分隔符
OFS: 输出字段分隔符 ,OFS=”#”指定输出分割符 为# RS 记录分隔符,默认值是换行符 \n ENVIRON:当前shell环境变量及其值的关联数组
FILENAME:被awk处理的文件名
案列1:输出所有账户
[root@server ~]# awk 'BEGIN{FS=":"} {print $1}' /etc/passwd
#在begin 模式下设置分隔符
案列2:使用 NR NF显示行数 列数
[root@server ~]# awk '{print NF,NR,$0} END{print FILENAME}' awk1.txt
#FILENAME 代表处理的文件名
[root@server ~]# awk '{print "第",NR,"行","有",NF,"列"}' > "/root/t1.txt" awk1.txt
案例 3:
[root@server ~]# awk -F ":" 'BEGIN{OFS="\t"} {print $1,$3}' /etc/passwd
案例4:
[root@server ~]# vim awk2.txt
zhangsan 68 88 92 45 71
lisi 77 69 43 52 84
wangwu 61 99 85 77 56
[root@server ~]# vim test.awk
{
print
print "$0:" , $0
print "$1:" , $1
print "$2:" , $2
print "NF:" , NF
print "NR:" , NR
print "FILENAME: " , FILENAME
}
[root@server ~]# awk -f test.awk awk2.txt
#执行过程如下
#awk按行处理,执行第一条命令
处理结果如下
zhangsan 68 88 92 45 71
$0: zhangsan 68 88 92 45 71
$1: zhangsan
$2: 68
NF: 6
NR: 1
FILENAME: awk2.txt
lisi 77 69 43 52 84
$0: lisi 77 69 43 52 84
$1: lisi
$2: 77
NF: 6
NR: 2
FILENAME: awk2.txt
wangwu 61 99 85 77 56
$0: wangwu 61 99 85 77 56
$1: wangwu
$2: 61
NF: 6
NR: 3
FILENAME: awk2.txt
面试题:查看文件中空白行的行号
[root@server ~]# awk '/^$/{print NR}' /etc/sos/sos.conf
#先使用awk筛选文件中的空白行,再使用awk对筛选出的内容进行指定操作
七.awk中的操作符
算数运算符:
算术运算符:+、-、*、/、% ^(指数) **(指数)(分别表示加、减、乘、除和取模 )
案例1: 使用算数运算符进行计算
[root@server ~]# awk 'BEGIN {x=2;y=3;print x+y , x-y , x/y , x%y , x^y , x**y}'
案例2:统计某个目录文件中占用的字节数
[root@server ~]# ll /etc | awk 'BEGIN{size=0} {size=size+$5} END{print "size is :", size/1024 , "KB"} '
#$5:第五列
#BEGIN中的内容在处理正文前执行,处理正文过程中不执行
#END中的内容在处理正文完毕后最后执行
#上述命令处理过程:
#使用 ll 查询文件内容使用管道符 | 将查询内容交给awk命令处理
#awk命令中BEGIN定义开头输出内容:将0赋值给size 正文处理过程中将第五列的值从第一行开始累加
#最后使用END机构一次性输出结果,若不使用END,则按照awk规则,处理一行文本即输出一次处理结果
赋值运算符 :
赋值运算符:= += -= /= %= ^=
-=
:是一个简写形式的赋值运算符,表示减去某个数并将其结果赋值给一个变量
[root@server ~]# awk 'BEGIN{a=5 ; print a+=5 , a-=5 , a/=5 }'
#上述命令处理过程:awk按行处理,每处理一行输出一个结果,先将5赋值给a,再将a=5时+5之后的值赋值给a,#此时a=10接着再将a的值-5之后赋值给a,最后将a的值/5之后赋值给a,最后输出结果
条件运算符:
格式: 条件表达式?表达式1:表达式2
注意:?: 类似于 条件语句 if else
案例: 输出最大值
[root@server ~]# vim awk3.txt
3 6
10 9
3 3
7 5
[root@server ~]# awk '{max=$1>$2?$1:$2 ; print NR , "max=", max }' awk3.txt
逻辑运算符:
&& || !(取反)
关系运算符
> (大于) < >= = == != ~(匹配) !~(不匹 配)
案例:显示本地IP地址
[root@server ~]# ifconfig ens160 | awk 'NR==2{print $2}'
案例:查询/etc/passwd 文件第三列小于10以下的行,仅输 出账户和UID
[root@server ~]# awk 'BEGIN{FS=":"} $3<10{print $1,$3}' /etc/passwd
其它运算符
++ -- + -
案例:
[root@server ~]# awk 'BEGIN{a=3 ; print a++,++a}'
#a++:置后自增:先输出a之后数值+1
#++a:置前自增:先数值+1再输出a
案例2:awk中操作数为字符串时参与算术运算会被转为数值0
[root@server ~]# awk 'BEGIN{a="china" ; print a++,++a}'
#将字符串赋值给a,a参与算数运算时将自动转化为数值0