awk的基本使用

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}' Records.txt

在该条指令中,省略了判断条件每一条记录都会执行该输出,而使用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]}'
  • 求出Java成绩的最高分
cat Record.txt | awk '$1!="Name" && $4 > max {max=$4} END{print "max mark is", max}'
  • 自定义输出数据格式

一般情况下简单的信息输出使用print即可,该输出可以直接输出所需要的信息,并自动换行.但是如果对数据输出格式有特别的要求的话,可以使用printf来进行定义.

printf 语句的形式如下:

printf(format, value1, value2, ..., valuen)

format是格式控制字符串,其中包含了需要逐字输出的字符串和需要输出的数据的指定格式.数据格式一般使用%+对应的数据格式表示.printf不能自动换行,所以对于行数据输出,需要在format中手动添加"\n".

姓名按照至少10个字符左对齐,平均成绩使用6位数字且小数部分2位输出

cat Record.txt | awk '$1!="Name"{printf("%-8s %6.2f\n", $1, ($2+$3+$3)/(NF-1))}'

也可以在format中添加需要逐字输出的定义信息:

cat Record.txt | awk '$1!="Name"{printf("%-8s :average is %6.2f\n", $1, ($2+$2+$3)/ (NF-1))}'
  • 排序

使用sort对输出结果进行排序,默认会对第一个域(Field)进行排序.

按照姓名的升序进行排序查看C语言成绩

cat Record.txt | awk '$1!="Name"{printf("%-8s %6.2f\n", $1, $3)}' | sort

按照姓名的降序进行排序查看Java语言成绩

cat Record.txt | awk '$1!="Name"{printf("%-8s %6.2f\n", $1, $4)}' | sort -r

按照Java成绩升序输出姓名和Java成绩(-b忽略前导的空白区域 -k 指定排序的列)

cat Record.txt | awk '$1!="Name"{printf("%-8s %6.2f\n", $1, $4)}' | sort -b -k 2
  • 控制语句
    • if-else语句
    • while语句
    • for语句

if-else是常用的控制语句,其实在上边使用到的条件语句都是一种省略形式的if-else语句.

awk 'NR!=1{print $1,$3}' Record.txt
//等价于
awk '{if(NR!=1)print $1, $3}' Record.txt


awk 'BEGIN{OFS="\t"} $1!="Name"{print $1, $3}' Records.txt
//等价于
awk 'BEGIN{OFS="\t"} {if($1!="Name") print $1, $3}' Records.txt

while主要用于循环实现,例如将Record.txt中的信息逆序输出:

#定义一个实现文本script
{list[NR]=$0}
END{
    j=NR
    while(j>0) {
    print list[j];
    j--;
    }
}

#使用awk -f执行脚本
cat Record.txt | awk -f script

同样也可以使用for实现:

#定义一个实现文本script
{list[NR]=$0}
END{
    for(j=NR;j>0;j--) {
    print list[j];
    }
}

#使用awk -f执行脚本
cat Record.txt | awk -f script

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值