0

私は2つのファイルを持っています

ファイル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  

要件は、行ごとに比較し、次に列ごとに比較することです。この 2 つの出力ファイルを作成する必要があります。最初に、file2 からの行 3 があり、これらの行が file2 で新規であることを示します。2 番目のファイルには次の出力が含まれます。

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  

しかし、2 番目の出力ファイルを生成する方法がわかりません。

4

1 に答える 1

1

仕様の完成:

  • 行番号はファイルに物理的に存在しますか? はい
  • File1 のエントリが File2 のエントリと一致することを示す列の組み合わせはどれですか? 行番号
  • 見出し行はファイルに物理的に存在しますか? いいえ(ただし、後で気が変わります)
  • ファイル内のデータはソートされていますか? いいえ
  • File1 には存在するが File2 には存在しないレコードはどのように処理されますか? 指定されていませんが、おそらく 3 番目の出力ファイルが必要です。

答えは「削除されたレコード」の問題を無視します。

質問は、このロジックが 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";
                      }
                  }
                }'

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 の演習です。

于 2013-03-29T16:44:44.877 に答える