awk是linux及Unix环境中现有的功能最强大的数据处理引擎之一,名字以三位创始人的名字命名(Alfred Aho,Peter Jay Weinberger, Brian Wilson Kernighan),距今已经有近40年的历史。
Man对其定义如下:
awk – 样式扫描与文本处理工具
本篇主要记录自己在日常工作中需要用到awk处理一些数据的典型案例。
文件样例:
$cat a.txt 111 111 222 222 333 333 444 444 555 555 666 666 777 777 888 888 999 999 000 000 444 555 111 222
$cat b.txt 333 444 444 666
这里先介绍下本文用的较多的awk内部变量
$0 – 存放当前处理行内容。
$1-n – 该行的第几个字段,段是依靠分隔符分隔。
NR – 记录处理的行号,从1开始,不断累加。
FNR – 当前文件记录,与NR不同的是,这个值会是各个文件自己的行号。
如果你想对文件a.txt第一列相同的行去重,且保留第一个出现
$awk '!a[$1]++' a.txt 111 111 222 222 333 333 444 444 555 555 666 666 777 777 888 888 999 999 000 000
a[]是一个数组,$1是a.txt第一列的取值,a[$1]++表示当$1出现一次就加1,注意这里++和C的处理方式相同,是先处理再加,那么当$1第一次出现时!a[$1]为true,第二次出现时为false。可以思考下$awk ‘a[$1]++’ a.txt会输出什么:)
如果你想对文件a.txt第一列相同的行去重,且一个重复的都不保留
$awk 'NR==FNR{a[$1]++} NR>FNR&&a[$1]==1' a.txt a.txt 222 222 333 333 555 555 666 666 777 777 888 888 999 999 000 000
当NR==FNR时,这时是处理第一个a.txt(注意两个a.txt是同一个文件),a[$1]++记录第一列单元出现的次数;NR>FNR时,进入第二个a.txt处理,a[$1]==1表示第一列元素仅仅只出现了1次时为true,打印输入行。
原理就是先扫描一遍a.txt记录我们需要的信息,然后再扫描一遍a.txt按要求输出我们需要的信息。
如果你想对文件a.txt第一列相同的行留重,且保留所有重复的
$awk 'NR==FNR{a[$1]++} NR>FNR&&a[$1]>1' a.txt a.txt 111 111 444 444 444 555 111 222
与上面的类似,这里判定a[$1]>1,表示第一列的元素至少已经出现过2次。
如果你想对文件a.txt第二列求和,如果第一列相同就累加
$awk '{a[$1]+=$2}END{for(i in a) print i,a[i]}' a.txt 111 333 777 777 222 222 888 888 333 333 999 999 444 999 555 555 000 0 666 666
如果你想对文件a.txt第二列求平均,第一列相同就累加除以出现次数
$awk '{a[$1]+=$2;b[$1]+=1}END{for(j in a )print j,a[j]/b[j]}' a.txt 111 166.5 777 777 222 222 888 888 333 333 999 999 444 499.5 555 555 000 0 666 666
如果你想找出文件a.txt,b.txt中有相同第一列的行
$awk 'NR==FNR{a[i++]=$0;b[j++]=$1;c[$1]++} \ NR>FNR{k=0;for(m in b) if(b[m]==$1){if(a[m]){print a[m];delete a[m]}k=1} if(k==1) print $0} \ END {for(m in b) if(c[b[m]]>1 && a[m]) print a[m]}' a.txt b.txt 333 333 333 444 444 555 444 444 444 666 111 222 111 111
数组a[]用来储存a.txt的行信息,b[]用来索引a.txt的第一列,c[]用来行计数;进入b.txt后我们对于b.txt的每一行循环查找b[],看有没有相同的第一列,如果有我们输出a[](记得delete a[],否则会下一次索引到会重复输出),最后再根据标记k打印符合条件的b.txt行。END后面处理主要为了处理a.txt文件中本身已经存在的重复行,但是没在扫描b.txt中输出的。
其实这里也可以用
$cat a.txt b.txt > c.txt $awk 'NR==FNR{a[$1]++} NR>FNR&&a[$1]>1' c.txt c.txt
a.txt,b.txt文件不太大时推荐使用后者,文件若过大可能会导致cat异常出错。
处理两个或者多个文件数据的基本思路是,看需求能不能合并,如果可以合并就将其最简化处理;涉及到文件拼接、修改格式,用好if/print,判定和组装自己需要的格式。
(全文结束)
转载文章请注明出处:漫漫路 - lanindex.com