![比较 2 个制表符分隔文件并输出与列标题的差异](https://linux22.com/image/55249/%E6%AF%94%E8%BE%83%202%20%E4%B8%AA%E5%88%B6%E8%A1%A8%E7%AC%A6%E5%88%86%E9%9A%94%E6%96%87%E4%BB%B6%E5%B9%B6%E8%BE%93%E5%87%BA%E4%B8%8E%E5%88%97%E6%A0%87%E9%A2%98%E7%9A%84%E5%B7%AE%E5%BC%82.png)
我想比较同一列上的 2 个相似文件。这些文件将具有相同的标头。
file1.txt
mem_id Date Time Building
aa bb cc dd
ee ff gg hh
ii jj kk ll
file2.txt
mem_id Date Time Building
aa bb cc dd
ee ff 2g hh
ii jj kk 2l
Command
awk 'NR==FNR{for(i=1;i<=NF;i++){A[i,NR]=$i}next} {for(i=1;i<=NF;i++){if(A[i,FNR]!=$i)\
{print "ID#-"$1": Column",i"- File1.txt value=",A[i,FNR]" / File2.txt value= "$i}}}'\
file1.txt file2.txt
Current Output
ID#-ee: Column 3- File1.txt value= gg / File2.txt value= 2g
ID#-ii: Column 4- File1.txt value= ll / File2.txt value= 2l
Desired Output
mem_id#-ee: Time- file1.txt value= gg / file2.txt value= 2g
mem_id#-ii: Building- file1.txt value= ll / file2.txt value= 2l
我非常接近。但我希望得到一些改进方面的帮助。
1-我想用实际的列标题(时间、建筑物等)替换“第 3 列”和“第 4 列”
2-我想动态收集输出中的文件名,而不必将其添加为命令的一部分(以使其通用)
3-我想要这个可编写脚本的。
任何帮助,将不胜感激。
答案1
使用awk
:
awk '
NR==1 {
for (i=1; i<=NF; i++)
header[i] = $i
}
NR==FNR {
for (i=1; i<=NF; i++) {
A[i,NR] = $i
}
next
}
{
for (i=1; i<=NF; i++)
if (A[i,FNR] != $i)
print "ID#-" $1 ": " header[i] "- " ARGV[1] " value= ", A[i,FNR]" / " ARGV[2] " value= "$i
}' file1.txt file2.txt
输出:
ID#-ee: Time- file1.txt value= gg / file2.txt value= 2g
ID#-ii: Building- file1.txt value= ll / file2.txt value= 2l
答案2
这是我认为可以完成这项工作的脚本:
#! /bin/bash
FILE1=$1
FILE2=$2
[[ -z $FILE1 || -z $FILE2 ]] && echo "USAGE: $0 FILE1 FILE2" && exit 1
join -j 1 $FILE1 $FILE2 |
awk '
NR == 1 { for (i = 1; i <= NF; i++) { header[i] = $i; }; NCOLS = (NF - 1)/2; }
NR > 1 { for (i = 2; i <= NCOLS + 1; i++) { if ($i != $(i+NCOLS)) {print header[1]"#-"$1": "header[i]"- '$FILE1' value=",$i" / '$FILE2' value= "$(i+NCOLS) } } }
'
我申请了一个join
以便我可以一次性阅读它们。
使用NR == 1
,我将第一行读取到数组中(以便稍后可以重用它们。
由于我使用了join
,如果两个文件都有n
列,则组合输出也有2n-1
列(用于合并的列)。因此,我将列数(不包括公共列)保存到NCOLS
.