在unix中逐列比较

时间:2013-03-29 06:34:50

标签: unix awk

我有两个文件

File1

Row   Col1  Col2  Col3  Col4  
1      A     B    C     D  
2      E     F    G     H

File2

Row   Col1  Col2  Col3  Col4  
1      A     Z    C     D  
2      E     F    Y     H  
3      M     N    O     P  

要求是逐行,然后逐列比较。使用这两个输出文件需要创建。 首先是来自file2的第3行,它指出这些行在file2中是新的。 第二个文件将具有此输出:

FileName  Row  ColName  ColValue  
File1     1     Col2    B (--this is old value)  
File2     1     Col2    Z (--this is new value) 

File1     2     Col3    G  
File2     2     Col3    Y  

现在获取file1中缺少但在file2中存在的行可以通过

完成
awk 'NR==FNR{a[$1]++;next;}!($0 in a)' file2 file1  

但不确定如何生成第二个输出文件。

1 个答案:

答案 0 :(得分:1)

完成规范:

  • 行号是否实际存在于文件中?
  • 列的哪些组合告诉您File1中的条目与File2中的条目匹配? 行号
  • 标题行是否实际存在于文件中? 否(但我们稍后会改变主意)
  • 文件中的数据是否排序? 假设没有
  • 如何处理File1中但不存在于File2中的记录? 未指定,但可能需要第三个输出文件。

答案将忽略“删除的记录”问题。

问题是观察到这个逻辑找到了在File2中插入的记录:

awk 'NR==FNR{a[$1]++;next;}!($0 in a)' file2 file1

接近正确;它应该是!($1 in a)。需要显式打印才能将输出发送到文件。对于其余的逻辑,我们可以非常容易地发现字段中的变化:

awk 'NR == FNR  { a[$1] = $0; next }
     !($1 in a) { print $0 > "ofile.1"; next }
                { split(a[$1], old);
                  for (i = 2; i <= NF; i++)
                  {
                      if ($i != old[i])
                      {
                          format = "%-8s  %4d  %d  %s\n"
                          printf format, "File1", $1, i, $i     > "ofile.2";
                          printf format, "File2", $1, i, old[i] > "ofile.2";
                      }
                  }
                }'

这在给定的假设下产生合理的输出(标题行不存在)。如果实际上标题行存在,那么你必须捕获它们并使用它们(以及文件名):

awk 'FNR == 1   { file[++num] = FILENAME; for (i = 1; i <= NF; i++) head[i] = $i; next }
     NR == FNR  { a[$1] = $0; next }
     !($1 in a) { print $0 > "ofile.1"; next }
                { split(a[$1], old);
                  for (i = 2; i <= NF; i++)
                  {
                      if ($i != old[i])
                      {
                          format = "%-8s  %4d  %-4s  %s\n"
                          printf format, file[1], $1, head[i], $i     > "ofile.2";
                          printf format, file[2], $1, head[i], old[i] > "ofile.2";
                      }
                  }
                }'

要在第二个输出文件上获得正确的标题,您需要进行一些小的调整:

awk 'NR == 1    { printf "%-8s  %4s  %-7s  %s\n", "Filename", "Row", "Colname", "Colvalue" > "ofile.2" }
     FNR == 1   { file[++num] = FILENAME; for (i = 1; i <= NF; i++) head[i] = $i; next }
     NR == FNR  { a[$1] = $0; next }
     !($1 in a) { print $0 > "ofile.1"; next }
                { split(a[$1], old);
                  for (i = 2; i <= NF; i++)
                  {
                      if ($i != old[i])
                      {
                          format = "%-8s  %4d  %-7s  %s\n"
                          printf format, file[1], $1, head[i], $i     > "ofile.2";
                          printf format, file[2], $1, head[i], old[i] > "ofile.2";
                      }
                  }
                }' File1 File2

此示例输出为:

ofile.1

3      M     N    O     P

ofile.2

Filename   Row  Colname  Colvalue
File1        1  Col2     Z
File2        1  Col2     B
File1        2  Col3     Y
File2        2  Col3     G

如果你想在每条记录后留空行,这是一个微不足道的修改 - OP的练习。

相关问题