如何用标准Unix命令按1:1匹配找出文件的异同行?
用标准Unix命令实现1:1匹配的文件行对比需求
需求说明
现有两个文本文件,需要完成以下三类行的识别:
- (a) 两文件共有的行(要求1:1匹配:文件1的一行只能匹配文件2的一行,不能一个文件的一行对应另一个文件的多行)
- (b) 仅存在于第一个文件的行
- (c) 仅存在于第二个文件的行
常规方法如cat+uniq、comm或fgrep无法满足这种1:1的匹配规则,以下是具体示例:
示例文件内容
File 1
A B C A B C
File 2
A B A D
预期输出结果
Common in both: A, B, A In file 1 only: C, B, C In file 2 only: D
解决方案:使用awk实现
可以用awk脚本实现这种精确的1:1匹配逻辑,脚本代码如下:
BEGIN { OFS = ", " } # 遍历第一个文件,统计每行出现次数 NR == FNR { cnt1[$0]++ next } # 遍历第二个文件,匹配公共行并更新计数 { if (cnt1[$0] > 0) { cnt1[$0]-- common[++c_idx] = $0 } else { only_file2[++f2_idx] = $0 } } # 处理剩余行并输出结果 END { # 收集文件1中未匹配的行 for (line in cnt1) { for (i=1; i<=cnt1[line]; i++) { only_file1[++f1_idx] = line } } # 输出公共行 printf "Common in both: " for (i=1; i<=c_idx; i++) { printf "%s%s", common[i], (i == c_idx ? "\n" : OFS) } # 输出仅文件1的行 printf "In file 1 only: " for (i=1; i<=f1_idx; i++) { printf "%s%s", only_file1[i], (i == f1_idx ? "\n" : OFS) } # 输出仅文件2的行 printf "In file 2 only: " for (i=1; i<=f2_idx; i++) { printf "%s%s", only_file2[i], (i == f2_idx ? "\n" : OFS) } }
使用方法
- 将上述代码保存为
match_lines.awk - 在终端执行命令:
awk -f match_lines.awk file1 file2
逻辑说明
- 首先遍历第一个文件,用数组
cnt1记录每行的出现次数 - 遍历第二个文件时,若当前行在
cnt1中还有剩余计数,就将其归入公共行列表,并减少对应计数;否则归入仅文件2的行列表 - 最后遍历
cnt1数组,将剩余有计数的行按次数归入仅文件1的行列表 - 最终按要求格式输出三类结果
内容的提问来源于stack exchange,提问作者pbere
相关产品推荐
相关产品推荐

