awk '!arr[$0]++'对文件进行处理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了awk '!arr[$0]++'对文件进行处理相关的知识,希望对你有一定的参考价值。
awk ‘!arr[$0]++‘后跟文件,可以过滤掉重复的行。
如下面的文件经过处理。
[[email protected] ~]# 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 [[email protected] ~]# 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/fstab awk ‘!/^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。
[[email protected] ~]# awk BEGIN‘{i=1;print i++}‘ 1 [[email protected] ~]# awk BEGIN‘{i=1;print ++i}‘ 2 [[email protected] ~]# awk BEGIN‘{a=0;print a++}‘ 0 [[email protected] ~]# awk BEGIN‘{a=0;print ++a}‘ 1
而当i值为0时,print i++依旧输出0,结果为假。print ++i结果为1,即为真了。
awk对文本进行处理时,$0对应每行文本,即字符串,arr[$0]下面为字符串,是关联数组。
而当变量被赋值为字符串时,变量对应的数值则为0。
[[email protected] ~]# awk BEGIN‘{a="shhkjl";print a}‘ shhkjl [[email protected] ~]# awk BEGIN‘{a="shhkjl";print !a}‘ 0 [[email protected] ~]# awk BEGIN‘{a="shhkjl";print a++}‘ 0 [[email protected] ~]# 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为假,其他数值则均为真。
[[email protected] ~]# awk BEGIN‘{a=-1;print !a}‘ 0 [[email protected] ~]# 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]++‘后跟文件,会把重复的行过滤掉,只打印非重复的行。
本文出自 “RightNow” 博客,请务必保留此出处http://amelie.blog.51cto.com/12850951/1967273
以上是关于awk '!arr[$0]++'对文件进行处理的主要内容,如果未能解决你的问题,请参考以下文章