如何用cat和grep批量匹配文本姓氏并统计不匹配条目数量?
问题描述
我有两个文本文件:input.txt和reference.txt,内容示例如下:
input.txt内容:
john j william james slate david wallace ..
reference.txt内容:
joseph william raj kumar william hague david alexander
我需要检查input.txt中每行的姓氏(每行最后一个字段)是否存在于reference.txt的姓氏列表里,统计匹配和不匹配的条目数量,重点关注不匹配的计数。之前手动是逐个用grep查找参考文件里的姓氏:
cat input.txt | grep "<the_last_name>"
现在想程序化实现这个操作,拿到不匹配的计数。
方法一:用awk实现(推荐)
awk能直接处理两个文件,先把参考文件的姓氏存进数组,再遍历输入文件检查每行的姓氏是否在数组中,同时统计计数。
执行命令:
awk ' NR == FNR { surnames[$NF] = 1; next } { if ($NF in surnames) { matched++ } else { unmatched++ # 要是想看到具体哪些行不匹配,取消下面这行注释 # print $0 } } END { print "匹配条目数: " matched print "不匹配条目数: " unmatched } ' reference.txt input.txt
简单说明:
- 先处理
reference.txt,把每行最后一个字段(也就是姓氏)存入surnames数组 - 接着处理
input.txt,检查每行最后一个字段是否在数组里,分别累加匹配和不匹配的数量 - 最后在END块输出统计结果,需要查看不匹配的具体行就取消注释
print $0
方法二:用grep+shell命令组合实现
先提取参考文件的姓氏生成匹配模式,再用grep匹配输入文件的行,最后计算数量:
- 先生成参考姓氏的正则匹配串:
REF_SURNAMES=$(awk '{print $NF}' reference.txt | sort | uniq | tr '\n' '|' | sed 's/|$//')
- 统计匹配和不匹配的数量:
TOTAL=$(wc -l < input.txt) MATCHED=$(grep -E "\b($REF_SURNAMES)$" input.txt | wc -l) UNMATCHED=$((TOTAL - MATCHED)) echo "匹配条目数: $MATCHED" echo "不匹配条目数: $UNMATCHED"
简单说明:
awk '{print $NF}' reference.txt提取所有姓氏,sort | uniq去掉重复的姓氏tr '\n' '|' | sed 's/|$//'把姓氏拼接成xxx|yyy|zzz的正则格式grep -E "\b($REF_SURNAMES)$"匹配输入文件中以参考姓氏结尾的行(\b是单词边界,避免类似wall匹配wallace这种误判)- 用输入文件的总行数减去匹配数,就得到不匹配的数量
内容的提问来源于stack exchange,提问作者JohnJ
相关产品推荐
相关产品推荐

