正所谓,知己知彼百战不殆,想要拿下awk,必需了解它的前世今生;
一、它可以做什么
1、 awk 是一种编程语言, 可以用作linux或者Unix的bash脚本中;也可以单独放在一个文件中,通过awk命令解释器运行;
【这里只关注awk用作bash脚本中】
2、awk 主要功能是,基于指定的规则,对文本或者数据做浏览和提取操作; 其处理原则为:逐行扫描文件,从第一行到最后一行,寻找匹配指定规则的内容。 【awk命令的主要功能是对文本做提取操作,所以,bash脚本编写中,awk经常与其它指令联合是使用:通过awk提取指定行,然后对该行做你所需要的操作。
二、它怎么使用呢
1、语法结构
awk 选项部分 '命令部分' 文件名
1)选项部分:为一些指定的参数,或者正则表达式;
2)命令部分:为需要运行的操作和指令,一般是用『 '{}' 』包围起来,用来表示执行的所有操作;
3)文件名: 就是我们要处理的文件;
【基本的awk 指令语法构成就是如上所示,也有一些更高阶的操作,这个后续再学习】
2、一些基本概念 【写在前面的东西】
1)分隔符和域
分隔符,就是语法结构中的『选项』部分, awk指令中,通过 -F 来定义字段的分隔符; awk指令默认的分隔符为空格,如果要处理的文件时以空格分割,则无需指定选项 -F ; 如果是通过除空格之外的其它字符分割,则必需指定-F ;
域: 定义了分隔符,则比如会有文本被分割成一段一段的, 这里统称为域; 域的标记符为:$1, $2, $3 ... $n ; 其中,$0 表示所有的域; 一个栗子:
一、定义文件【文件包含多列,列之间通过逗号分割】:
vim 1
序号,姓名,年龄,职业$
1,张三,19,学生$
2,李四,25,程序员$
3,王五,40,教师$
执行: awk -F , '{print $0}' 1
输出结果为:
序号,姓名,年龄,职业
1,张三,19,学生
2,李四,25,程序员
3,王五,40,教师
执行:awk -F , '{print $1}' 1
输出结果为:
序号
1
2
3
【解析】: -F 定义分隔符为逗号; 如果是以其它字符分割,则直接更换即可;
$0 定义域,这里输出全部域; 【可以通过域标识符,更换输出的域, 比如$1, 则只输出第一列】
1 为我定义的文件名字;
【备注】若是以其他分隔符做为分割,则直接替换 参数-F 的取值即可;如下:
定义文件【文件包含多列,以\t分割】
vim 3
序号^I姓名^I年龄^I职业^I去年工资^I今年工资$
1^I张三^I19^I学生^I1200^I1000$
2^I李四^I25^I程序员^I10000^I15000$
3^I王五^I40^I教师^I5000^I6000$
执行:awk -F \t '{print $2}' 3
输出结果为:
姓名
张三
李四
王五
【解析】: 此处,文件以\t分割,则对应-F 参数值改为\t, 则可以正确提取;
同理,可以以\n 分割;
2)模式和动作
模式和动作,位于语法结构中的『命令部分』, 故需要使用 '{ }' 包含起来;
他们说,awk语句,是由『模式』和『动作』两部分组成的;那么什么是模式,什么是动作呢?
动作:就是,定义对数据的具体操作;【也就是一些列的操作指令】;
模式:则定义了『动作』被触发的条件;
【可以是条件语句、正则匹配、复合语句等】;
【当然了,这并非必需的,若没有定义模式,则动作将保持时刻被触发的状态】
【模式以关键词BEGIN和END来标识, 其中BEGIN 定义在 动作之前执行; END定义的内容则在动作之后执行】
一个栗子:
还是文件: 1;
执行如下指令:
$ awk -F , 'BEGIN {print "---start print the file---"} {print $2} END {print "---the end---"}' 1
输出结果为:
---start print the file---
姓名
张三
李四
王五
---the end---
#解析:
1、-F: 定义分隔符,不做解释;
2、'BEGIN {print "---start print the file---"} {print $2} END {print "---the end---"}' 为模式定义和动作定义; 单引号不能省略;
1)其中 BEGIN {print "---start print the file---"} 定义动作开始前执行的操作;
2){print $2} 为动作定义;
3) END {print "---the end---"}' 定义动作结束后执行的操作;
4)每一个操作,需要{};
三、一些常用到的操作符 和 内置变量、内置函数;
1、定义了一个文件 1 ,文件中包含内容为:
2、定义文件nihao,文件中包含内容为:
1、 awk指令中可以使用的操作符:
操作符 | 操作指令 【指令部分,需要用双引号表示字符串】 | 作用 |
< 、<= 、 > 、 >= | awk -F , '{if ($5 < $6) print $2 "工资涨了"}' 1 输出: 李四工资涨了 王五工资涨了 | 比较文件中,第6列和第5列数值大小,满足要求,则输出; |
== 、 != | awk -F , '{if ($2=="李四") print $2 "在表中"}' 1 输出: 李四在表中 | 用于精确匹配; 和 精确不匹配 |
/[Pp]/ | awk '/[pP]/' nihao 输出: 前两行,因为前两行中包含了P 或者p | 用来匹配大小写, |
~ 『匹配正则表达式』 | 待补充 | |
!~ 『不匹配正则表达式』 | 待补充 |
2、awk 指令的内置变量
1)NF
[作用及其应用场景]:
A、awk按行读取文本, NF标识每一行的字段数【即列数】;【 直接输出'{print NF}', 则可以输出该行的列数;】
B、$NF 标识,该行的最后一列; 处理文本时,可能每一行列数不同,获取最后一列时,可以使用该方法;
C、这里的字段数,是根据指定分隔符分割后的字段数
[举个栗子]:
文件内容:
序号,姓名,年龄,职业,去年工资,今年工资
1,张三,19,学生,1200,1000
2,李四,25,程序员,10000,15000
3,王五,40,教师,5000,6000
执行1:awk -F , '{print NF}' 1
结果为:【输出每一行的列数】
6
6
6
6
执行2:awk -F , '{print $NF}' 1
结果为:【输出最后一列】
今年工资
1000
15000
6000
2)NR
[作用及其应用场景]:
A、AWK 按行读取文本, NR 标识每一行的行号;
B、可以根据行号,实现对应的筛选;
【举个栗子】:
文件内容:
序号,姓名,年龄,职业,去年工资,今年工资
1,张三,19,学生,1200,1000
2,李四,25,程序员,10000,15000
3,王五,40,教师,5000,6000
执行1:awk '{print NR}' 1
结果为:
1
2
3
4
执行2: awk '{if (NR>3) print "输出行号大于3的记录:" $0}' 1
结果为:输出行号大于3的记录:3,王五,40,教师,5000,6000
3)FNR
[作用及其应用场景]:
A、FNR 也标识 文本的行号;
B、同NR的区别在于:
读取多个文件时, NR会将多个文件的行号都依次连起来,顺序获取;
FNR,则可以识别不同的文件开端, 每读到一个新的文件,行号从1开始;
【举个栗子】
文件a.txt
a,aa,aaa,1
b,bb,bbb,2
c,cc,ccc,3
d,dd,ddd,4
e,ee,eee,5
文件b.txt
a,aa,aaa,1
b,bb,bbb,2
c,cc,ccc
a,dd,ddd,4
e,ee,eee,5
执行1:awk '{print "NR:" NR "FNR:" FNR}' a.txt b.txt
结果为:
NR:1FNR:1
NR:2FNR:2
NR:3FNR:3
NR:4FNR:4
NR:5FNR:5
NR:6FNR:1
NR:7FNR:2
NR:8FNR:3
NR:9FNR:4
NR:10FNR:5
执行2:
awk -F ,'{if(NR==FNR){arry[NR]=$0} else{if(arry[FNR]!=$0){print FNR}}}' a.txt b.txt
结果为:
3
4