提一个简单的需求,求两个文件的join集合。具体举个例子:
file1:
1 sh wahaha
2 bj lebaishi
3 nj jack
4 sz rose
5 bj hahaha
file2:
bj 010
sh 021
过滤出file1的第二列的值与file2的第一列的值对应的相等的记录,用awk怎么实现?在这个问题的驱动之下,来整理一下awk。
一、awk工具简介
一个awk由三个部分组成:BEGIN语句块、END语句块和能够使用模式匹配的通用语句块。这三个部分是可选的,任何一个部分都可以不出现在脚本中。
语法为:
awk 'BEGIN {statements} {statements} END {end statements}'
例如:
awk 'BEGIN {i = 0} {i++} END {print i}' filename
上面这句话可以理解成打印filename的行数。当然,打印filename的行号还有很多方式,比如下面两句:
awk 'END{print NR}' filename
wc -l filename | awk '{print $1}'
二、awk工作原理
awk命令的工作方式如下:
(1)执行BEGIN{ commands }语句块中的语句
(2)从文件或stdin中读取一行,然后执行pattern{ commands }。重复这个过程,知道文件全部被读取完毕。
(3)当读至输入流(input stream)末尾时,执行END{ commands }语句块。
BEGIN语句块在awk开始从输入流中读取行之前被执行。这是一个可选的语句块,诸如变量初始化、打印输出表格的表头等语句通常都可以写入BEGIN语句块中。
END语句块和BEGIN语句块类似。END语句块awk从输入流中读取完所有的行之后即被执行。像打印所有行的分析结果这类汇总信息,都是在END语句块中实现的常见任务(例如,在比价过所有的行之后,打印出最大数)。它也是一个可选的语句块。
最重要的部分是pattern语句块中的通用命令。这个语句块同样是可选的。如果不提供该语句块,则默认执行{print},即打印读一个读取到的行。这就像是一个用来读取行的while循环,在循环体中提供了相应的语句。
每读取一行时,它就会检查该行和提供的样式是否匹配。样式本身可以是正则表达式、条件以及行匹配范围等。如果当前行匹配该样式,则执行{}中的语句。
三、awk常用参数
下面解释一下awk的常用参数:
·NR:整个脚本当前已经读取过的记录数,就是行号,从1开始。随着所读文件的数目,一直累加。
·FNR:同NR,不过是针对当前在读的文件记录数。每开始读一个新文件时,从1开始累加,相当于行号。读完一个文件后就会清0,新的文件又会从1开始。
·FILENAME:当前文件名
·$0:读取文件的当前行
·$n(n>0):第n列数据
·NR:一行记录的字段的数目,也就是列数。
四、具体实现
那么现在就说一下开头的那个需求怎么实现,先直接看看怎么写:
awk 'NR==FNR{a[$1]=$2;}NR!=FNR && a[$2] {print $0}' file2 file1
执行结果:
1 sh wahaha
2 bj lebaishi
5 bj hahaha
来解释一下:
首先处理file2中的数据,由于是第一个文件,那么NR==FNR是满足条件的,那么就会生成数组a(举例:a['sh']='021'),然后执行NR!=FNR,结果不满足条件,不向后处理,直到循环到处理file1文件。此时前半段不满足条件,但是后半段满足条件,而同时对于file1中的第二列在数组a中出现过,即a[$2]不为空,那么就执行打印file1中每一行的数据。
当然处理两个文件的时候有多种方式:
awk 'NR==FNR{ block_one; next} { block_two }' file1 file2
awk 'NR==FNR{ block_one } NR>FNR{ block_two }' file1 file2
awk 'NR==FNR{ block_one } NR!=FNR{ block_two }' file1 file2
Author:忆之独秀
Email:[email protected]
注明出处:https://blog.csdn.net/lavorange/article/details/80410290