0

我有两个文件

文件 1

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

文件2

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  

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

4

1 回答 1

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

此示例输出为:

文件.1

3      M     N    O     P

外地.2

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

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

于 2013-03-29T16:44:44.877 回答