awk的主要作用是在可以针对查找文本定义模块化功能,实现复杂的字符串操作.awk是一个行文本处理命令,会通过默认的记录分割符(RS)将文本分割为多个记录,然后使用域分割符(FS)来将记录内容进行分割并赋值给临时的变量进行相关的操作.
基本介绍
通过定义不同的条件完成指定的操作,基本格式如下:
awk '条件1 {动作 1} 条件2{动作 2} …' 文件名
- 条件(Pattern):
awk支持的主要条件类型
条件类型 条 件 说 明 awk保留字 BEGIN 在 awk 程序一开始,尚未读取任何数据之前执行。BEGIN 后的动作只在程序开始时执行一次 awk保留字 END 在 awk 程序处理完所有数据,即将结束时执行?END 后的动作只在程序结束时执行一次 关系运算符 > 大于 < 小于 >= 大于等于 <= 小于等于 == 等于。用于判断两个值是否相等。如果是给变童赋值,则使用"=” != 不等于 A~B 判断字符串 A 中是否包含能匹配 B 表达式的子字符串 A!~B 判断字符串 A 中是否不包含能匹配 B 表达式的子字符串 正则表达式 /正则/ 如果在“//”中可以写入字符,则也可以支持正则表达式
- 动作(Action)
- 格式化输出
- 流程控制
在默认处理中,awk会首先使用默认的记录分割符(Record Seperator,缩写为RS,默认的记录分割符为"\n")进行记录分割,而默认的记录分割符是"\n",所以首先会将文本按照"\n"进行划分为不同的记录;然后会使用默认的域分割符(Field Seperator,缩写为FS,默认的域分割符为" ")将单条记录分割为不同的域,使用$1,$2...进行临时存储,便于后续的操作.其中$0指代当前整条记录,$1指代当前的记录的第一个字段,$2指代当前记录中的第二个字段,依次类推.
简单实用
为了方便说明,创建一个文本文件,命名为records.txt
Name PHP C Java Note
Jack 98 89 90 swimming&basketball&hiking
Frank 87 66 78 climming;swimming;football
Duke 78 99 83 basketball
Ericy 88 89 90 basketball
- 首先尝试使用awk输出Records中的所有内容:
awk '{print}' Records.txt
#或者使用
awk '{print $0}'
在该条指令中,省略了判断条件每一条记录都会执行该输出,而使用print省略参数的情况下默输出整条记录,所以执行该条指令会输出所有的记录.而有的时候,也可以根据需要省略执行语句:
cat Records.txt| awk '/ac/'
省略时默认输入满足条件的行,以上的命令这样就可以筛选出所有包含ac的行.由此可见,条件和动作并不是必须的,在适当的情况下是可以省略的.
- 输出姓名和C语言的成绩
可以使用如下命令:
awk '{print $1,$3}' Record.txt
在该条指令中,由于读取的记录会按照默认的FS进行分割,所以一条记录中,姓名会被赋值给$1,PHP成绩赋值给$2,C语言成绩赋值给$3, Java成绩赋值给$4,所以只需要针对每条记录输出 $1,$3即可.得到如下输出:
Name C
Jack 89
Frank 66
Duke 99
Ericy 89
由于第一行的Name和C并不是一个记录而是一个描述字段,可不可以把他们去掉呢?当然可以,在awk中有两个自带的变量NR(Numner of row)和NF(Number of field),相当于行号和列号,所以只需要隔离掉第一行的输出就可达到目的.
awk 'NR!=1{print $1,$3}' Record.txt
当然,可以把第一行当作一个特殊的记录,输出时隔离掉这条特殊的记录就可以了,同样可以达到目的.
awk '$1!="Name"{print $1,$3}' Record.txt
由于在输出时使用","进行参数分割,awk在输出时会使用默认的域分割符进行各个字段的分割.这时候可能会觉得,如果能让每一列能够下对齐看起来会舒服很多.想要实现这个功能只需要设置一个自定义域输出分割符就可以了,例如可以这样:
awk '$1!="Name"{print $1 "\t" $3}' Records.txt
除了这样还可以使用另一种方式,那就是自定义域输出分割符(OFS).
- 自定义域输出分割符
在awk中包含了两个内置的条件保留关键字,BEGIN和END.关键字BEGIN可以保证在尚未读取任何数据之前执行,而关键字END可以保证在程序处理完所有数据之后执行,而且这两条指令都只执行一次.所以针对以上的域对齐需求可以使用自定义域输出分割符来实现:
awk 'BEGIN{OFS="\t"} $1!="Name"{print $1, $3}' Records.txt
在你需要的时候,还可以自定义FS,RS,OFS,ORS等来实现需求.
- 输出PHP成绩大于85的人员姓名
只需要在原来的输出条件上添加控制成绩的判断即可:
awk 'BEGIN{OFS="\t"} $1!="Name" && $2>85 {print $1}'
- 输出姓名以字母k结尾的人员的姓名和C语言成绩:
可以使用正则表达式来做筛选:
awk 'BEGIN{OFS="\t"} $1~/k$/{print $1, $3}' Records.txt
如果需要筛选不符合条件的人员姓名,只需要在条件前添加取反即可.例如查找姓名不是以字符k结尾的人员的姓名和C语言成绩:
awk 'BEGIN{OFS="\t"} $1!="Name" && !($1~/k$/){print $1, $3}' Records.txt
- 求出Java的平均成绩
在awk中可以自定义的变量,统计平均成绩首先就需要统计所有成绩的和,然后在END条只执行时求去平均成绩.
awk 'BEGIN{OFS="\t"} $1!="Name"{java=java+$4} END{print java/(NR-1)}' Records.txt
当然还也可以不使用NR,使用自定义计数变量来实现:
awk 'BEGIN{OFS="\t"} $1!="Name"{java=java+$4;counter=counter+1;} END{print java/counter}' Records.txt
- 求出Java的成绩分布
cat Record.txt | awk 'NR!=1{a[$4]++} END{for(I in a) print I "\t" a[i]}'
来源:CSDN
作者:朗清风
链接:https://blog.csdn.net/WangErice/article/details/103874496