如何用Linux命令筛选出现次数大于1的非重复单词?解决awk重复输出问题
如何用Linux Shell命令筛选出现次数大于1的单词?
需求说明
我需要处理一个文本文件,用sort tt.txt | uniq -c可以统计每个单词的出现次数,示例如下:
# cat tt.txt test this and that and test # sort tt.txt | uniq -c 2 and 2 test 1 that 1 this
但我只想返回出现次数大于1的单词,期望输出是:
and test
我能用Python的pandas实现,但需要纯Linux Shell脚本的解决方案。
遇到的问题:awk方案的异常
我尝试用awk命令,但结果不符合预期。比如给tt.txt追加三个"to"后:
# echo "to" >> tt.txt # echo "to" >> tt.txt # echo "to" >> tt.txt # awk '++a[$1] > 1' tt.txt and test to to
为什么"to"会重复出现?
解决方法
方法1:sort+uniq+awk组合(推荐)
先通过sort+uniq -c完成统计,再用awk筛选次数大于1的行,最后去掉计数部分保留单词(如果需要和原输出一致的空格对齐就用第二个命令):
# 仅输出单词 sort tt.txt | uniq -c | awk '$1 > 1 {print $2}' # 保留空格对齐格式 sort tt.txt | uniq -c | awk '$1 > 1 {sub($1 OFS, ""); print}'
执行后就能得到符合预期的输出:
and test
方法2:修复awk的重复问题
原awk命令++a[$1] > 1的问题在于:每处理一行就会递增计数,只要计数大于1就输出当前行。比如"to"出现第三次时,计数变为3,依然满足>1的条件,所以会再次输出,导致重复。
要让每个单词只输出一次,需要先统计所有单词的总次数,再在处理完所有行后统一输出:
# 带空格对齐的版本 awk '{a[$1]++} END {for (word in a) if (a[word]>1) printf "%8s\n", word}' tt.txt # 不带对齐的版本 awk '{a[$1]++} END {for (word in a) if (a[word]>1) print word}' tt.txt
这个命令会先遍历所有行统计次数,最后在END块里遍历统计结果,只输出次数大于1的单词,每个单词只会出现一次。
内容的提问来源于stack exchange,提问作者shantanuo
相关产品推荐
相关产品推荐

