Unix抽出で2つのTSVを比較し、キーとヘッダーの違いを印刷する方法は?

Unix抽出で2つのTSVを比較し、キーとヘッダーの違いを印刷する方法は?

タイトルと構造が同じ2つのファイルがあり、最初の列はキーです。

ファイル1:

key    val1 val2 val3 val4 val5
Item1  10   12   44   88   22
Item2  33   33   43   77   22
Item3  28   44   55   22   11
Item4  12   55   55   14   44

ファイル2:

key    val1 val2 val3 val4 val5
Item1  10   11   44   99   22
Item2  33   33   43   77   22
Item3  28   44   55   22   11
Item4  12   55   55   14   00

上記のファイルからわかるように、2つのファイルは2つの点で異なります。

  • item1のval2とval4が異なります。
  • 項目4のval5が異なります。

だから、どの項目のどのフィールドが異なるかを示す比較出力を生成したいと思います。出力は次のようになります。

Item1: val2,val4
Item4: val5

答え1

awk -v ref=file1 '
    {
        getline refline <ref

        if (NR == 1) split(refline, head)

        nf = split(refline, a)

        for (i = 1; i <= nf; ++i)
            if ($i != a[i])
                diffcol[++n] = i

        if (n > 0) {
            $0 = a[1]

            for (i = 1; i <= n; ++i)
                $(i+1) = head[diffcol[i]]

            print
            n = 0
        }
    }' file2

これにより、ファイルがfile2「参照ファイル」と比較されますfile1。 fromの行file2は一般的に読み込まれますが、fromの行はawkコード内の呼び出しと分割によってfile1明示的に読み取られます。getlineawksplit

このsplit(refline, head)ブロックは配列をheadヘッダーに設定してから読み込みますfile1。これは入力の最初の行でのみ行われますfile2

最初のループは2つのファイル間のフィールドとはdiffcol異なり、配列に追加されたフィールドの列番号を比較します。

1つ以上の違いが見つかると、最初のフィールドが出力され、その後にfile1他のフィールドのヘッダーが出力されます。file1

コードの書き方、ヘッダー行、および最初のフィールドも比較対象であるため、最初のフィールドで違いが見つかった場合は、おそらくその行の先頭にkey出力行も表示されます。最初のフィールド値file1)。

コードでは、2つのファイルの列数が同じであるとは想定していません。

質問のデータが与えられたら、このコードから次のような出力を取得できます。

Item1 val2 val4
Item4 val5

答え2

pasteawkすべてのレコードに同じ数のフィールドがあるとし、との組み合わせを使用します。

paste file1 file2 |
  awk -F'\t' '
    NR == 1 {cols = split($0, hdr) / 2; next}
    {
      diff = sep = ""
      for (i = 2; i <= cols; i++)
        if ($i "" != $(i+cols) "") {
          diff = diff sep hdr[i]
          sep = ","
        }
      if (sep) print $1": "diff
    }'

比較が常に語彙的になるように""比較の各側面に追加します。フィールドが数値のように見える場合は、そのフィールドを削除して数値で比較できます。!=000-0infinfinity

関連情報