设为首页 收藏本站
查看: 498|回复: 0

[经验分享] awk '!arr[$0]++'文件处理分析

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2017-9-21 09:07:58 | 显示全部楼层 |阅读模式
awk '!arr[$0]++'后跟文件,可以过滤掉重复的行。
如下面的文件经过处理。   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[iyunv@centos7 ~]# cat fstab

#
# /etc/fstab
# /etc/fstab
# /etc/fstab
# /etc/fstab
# /etc/fstab
# Created by anaconda on Tue Jul 11 20:07:17 2017
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 /                       xfs     defaults        0 0
UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 /                       xfs     defaults        0 0
UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 /                       xfs     defaults        0 0
UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 /                       xfs     defaults        0 0
UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 /                       xfs     defaults        0 0
UUID=a86604e8-9d34-4c3f-b3b3-fb3f3b72e356 /app                    xfs     defaults        0 0
UUID=e45a1265-9826-442b-9ce6-5f44440e8d0e /boot                   xfs     defaults        0 0
UUID=a86604e8-9d34-4c3f-b3b3-fb3f3b72e356 /app                    xfs     defaults        0 0
UUID=e45a1265-9826-442b-9ce6-5f44440e8d0e /boot                   xfs     defaults        0 0
UUID=f1eb3668-9539-4d4f-bae1-79f94029a101 swap                    swap    defaults        0 0
UUID=645fd6f5-da6f-458e-968d-02c7106a3b62 /home                   xfs
defaults,usrquota,grpquota    0 2
[iyunv@centos7 ~]# awk '!arr[$0]++' fstab

#
# /etc/fstab
# Created by anaconda on Tue Jul 11 20:07:17 2017
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
UUID=2fe39e58-8f02-49bf-b4b3-a59c56dd3907 /                       xfs     defaults        0 0
UUID=a86604e8-9d34-4c3f-b3b3-fb3f3b72e356 /app                    xfs     defaults        0 0
UUID=e45a1265-9826-442b-9ce6-5f44440e8d0e /boot                   xfs     defaults        0 0
UUID=f1eb3668-9539-4d4f-bae1-79f94029a101 swap                    swap    defaults        0 0
UUID=645fd6f5-da6f-458e-968d-02c7106a3b62 /home                   xfs     defaults,usrquota,grpquota    0 2




我们知道,awk是一门语言。它的语言格式和bash差别还是有些的。awk得益于高效的执行速率,使用time命令查看执行时间,awk里的循环远甩bash几条街。
awk '!arr[$0]++' a.txt会先执行!arr[$0],$0指整行,在此时把文件的整行当作关联数组的下标的意思。关联数组为下标为字符串的数组。awk和sed一样,都是对文件进行行处理。每次抽取一行,处理,再抽取下一行处理。
#!是取反。
awk语言格式如下:
awk [options] 'BEGIN{ action;… } pattern{ action;… } END{action;… }' file ..
这里的PATTERN是,根据pattern条件,过滤匹配的行,再做处理
(1)如果未指定:空模式,匹配每一行
(2) /regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来
    awk '/^UUID/{print $1}' /etc/fstabawk '!/^UUID/{print $1}' /etc/fstab
(3) relational expression: 关系表达式,结果为“真”才会被处理
    真:结果为非0值,非空字符串
    假:结果为空字符串或0值
(4) line ranges:行范围startline,endline:/pat1/,/pat2/ 不支持直接给出数字格式
    awk -F: ‘/^root\>/,/^nobody\>/{print $1}'/etc/passwd
    awk -F: ‘(NR>=10&&NR<=20){print NR,$1}'/etc/passwd
(5) BEGIN/END模式BEGIN{}: 仅在开始处理文件中的文本之前执行一次END{}:仅在文本处理完成之后执行一次
awk '!arr[$0]++' a.txt这里用到的是第三条。!arr$[0]++为这里的关系表达式,但因为++的值是在对arr$[0]值取反后进行,这里并不会影响输入结果。

我们知道i++是先对i赋值,再++,++i则是先增加1,再把+1的值赋予i。
1
2
3
4
5
6
7
8
[iyunv@centos7 ~]# awk BEGIN'{i=1;print i++}'
1
[iyunv@centos7 ~]# awk BEGIN'{i=1;print ++i}'
2
[iyunv@centos7 ~]# awk BEGIN'{a=0;print a++}'
0
[iyunv@centos7 ~]# awk BEGIN'{a=0;print ++a}'
1



而当i值为0时,print i++依旧输出0,结果为假。print ++i结果为1,即为真了。

awk对文本进行处理时,$0对应每行文本,即字符串,arr[$0]下面为字符串,是关联数组。
而当变量被赋值为字符串时,变量对应的数值则为0。
1
2
3
4
5
6
7
8
[iyunv@centos7 ~]# awk BEGIN'{a="shhkjl";print a}'
shhkjl
[iyunv@centos7 ~]# awk BEGIN'{a="shhkjl";print !a}'   
0
[iyunv@centos7 ~]# awk BEGIN'{a="shhkjl";print a++}'
0
[iyunv@centos7 ~]# awk BEGIN'{a="shhkjl";a++;print a}'  
1



这样,对其取反,值则为1。

awk如果不跟输出条件,就默认输出$0,即默认输出本行的全部内容。
arr[$0]第一次读取文件的第一行,因为文本内容被当作字符串处理,则arr[$0]一直为假,即arr[$0]=0,对arr[$0]取反则为真,即!arr[$0]=1,则会执行打印操作。
至于++,++的结果并不输出,所以对当前行关系表达式的真假判断不会造成影响,但++的结果会在对下一行进行处理时影响arr[$0]的结果,虽然下一行的arr[$0],又是另一个值了。

以上面fastb的处理为例。
awk首先抽取第一行,此时arr[$0]为arr[""],arr[""]的值为空字符串,即arr[""]=0,则有!arr[""]=1,打印本行。++是对arr[""]执行的操作。arr[""]原值为0,++后则为1。
也就是说!arr[$0]++,其实是两个分开的并行动作,!arr[$0]是对关系表达式取反,arr[$0]++对arr[$0]进行+1的操作。!arr[$0]决定本行是否打印,arr[$0]的值则因为下标值的不同每次更换,如果遇不到相同行,则根本不会再起作用。
arr数组的第一个数为arr[""],在处理完第一行后,arr[""]被赋值为1。
对第二行处理时arr[$0]就成了arr["#"],arr["#"]="#",字符串,则arr["#"]=0,!arr["#"]=1,打印。
只要变量值为字符串,则变量值均为0。0为假,其他数值则均为真。
1
2
3
4
[iyunv@centos7 ~]# awk BEGIN'{a=-1;print !a}'        
0
[iyunv@centos7 ~]# awk BEGIN'{a=10;print !a}'  
0



直到遇到相同的行,如上面fstab文件中有重复的# /etc/fstab行,在对第一个# /etc/fstab行执行完操作后,arr["# /etc/fstab"]++后值为1。对第二个# /etc/fstab行进行处理时,arr[$0]即arr["# /etc/fstab"],由于数组中已有此元素,则不在重新赋值,arr["# /etc/fstab"]值为1,对其取反,!arr["# /etc/fstab"]=0,关系表达式为假,则本行不再打印。
然后,由于++,arr["# /etc/fstab"]的值则为2。
对第三个# /etc/fstab行进行处理,取反后依然为假,不输出。
结果就是,awk '!arr[$0]++'后跟文件,会把重复的行过滤掉,只打印非重复的行。


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-404810-1-1.html 上篇帖子: linux /etc/inittab 的六个运行级别简单理解 下篇帖子: Linux下 分割日志大文件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表