awk实用技巧

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

Leave a Comment

Your email address will not be published.