web-dev-qa-db-ja.com

ファイルの特定の列でDiffを使用する

ファイルの特定の列でdiffを使用することは可能ですか?

file1

Something  123 item1
Something  456 item2
Something  768 item3
Something  353 item4

file2

Another   123 stuff1
Another   193 stuff2
Another   783 stuff3
Another   353 stuff4

出力(予想)

Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3

各ファイルの2列目をdiffしたい場合、結果には差分列が含まれますが、行全体が含まれます。

6
kickass13

awkは、ファイルの列を比較するための優れたツールです。たとえば、次の回答を参照してください。 異なるファイルの2つの列を比較し、一致する場合は印刷 -一致する列の行を印刷するための同様の回答があります。

一致しない行を印刷したいので、file2の行を印刷するawkコマンドを作成できます2はfile1:にnotが見られませんでした:

$ awk 'NR==FNR{c[$2]++;next};c[$2] == 0' file1 file2
Another   193 stuff2
Another   783 stuff3

上記の質問 のterdonによって同様に説明されたように、

  • NR==FNR:NRは現在の入力行番号、FNRは現在のファイルの行番号です。 2つは、最初のファイルが読み取られている間だけ等しくなります。
  • c[$2]++; next:これが最初のファイルの場合、2番目のフィールドをc配列に保存します。次に、次の行にスキップして、これが最初のファイルにのみ適用されるようにします。
  • c[$2] == 0:elseブロックは、これが2番目のファイルである場合にのみ実行されるため、このファイルのフィールド2がすでに表示されているかどうかを確認し(c[$2]==0)、表示されている場合は、行を出力します。 awkでは、デフォルトのアクションは行を出力するため、c[$2]==0がtrueの場合、行が出力されます。

しかし、file2の列2が一致しないfile1の行も必要です。これは、同じコマンドで位置を交換するだけで取得できます。

$ awk 'NR==FNR{c[$2]++;next};c[$2] == 0' file2 file1
Something  456 item2
Something  768 item3

したがって、awkを2回使用して、必要な出力を生成できます。おそらく、より多くのawkの専門知識を持つ誰かが1つのパスでそれを行うことができます。

質問に/kshのタグを付けたので、kornシェルを使用していると想定します。 kshでは、diffの関数、たとえばdiffcol2を定義して、作業を簡単にすることができます。

diffcol2()
{
   awk 'NR==FNR{c[$2]++;next};c[$2] == 0' $2 $1      
   awk 'NR==FNR{c[$2]++;next};c[$2] == 0' $1 $2      
}

これはあなたが望む振る舞いを持っています:

$ diffcol2 file1 file2
Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3
10
Lars Rohrbach

Diffは(cutと組み合わせても)、これを処理するのに十分な柔軟性があるとは思いません。そして、本当に必要なのは、file1のキーで、file2にはない、またはその逆のキーであるようです。厳密には、行ごとの差分ではありません。入力ファイルが大きい場合は、Perlを使用しますが、小さいファイルの場合、このawkスクリプトは提供された入力に対して機能します。

%cat a.awk

BEGIN {
  while (getline < "file1") {
    line=$0;
    split(line,f," ");
    key=f[2];
    f1[key]=line
  }
  while (getline < "file2") {
    line=$0;
    split(line,f," ");
    key=f[2];
    f2[key]=line
  }
}
END {
  for (c in f1) {
    if (c in f2 == 0) print f1[c]
  }
  for (c in f2) {
    if (c in f1 == 0) print f2[c]
  }
}

そして、これはあなたがそれを実行する方法です(awkはパラメーターとして入力ファイルを想定しているので、/ dev/nullのトリックに注意してください:

%awk -f a.awk /dev/null
Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3
3
Ian McGowan