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

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

ファイルの特定の列に対してdiffを使用できますか?

ファイル1

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

ファイル2

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結果に差分列が含まれますが、行全体が含まれます。

答え1

awkファイル列を比較するためのより良いツールです。たとえば、次の質問に対する回答をご覧ください。異なるファイルの2つの列を比較し、一致した場合に印刷します。- 列に一致する行を印刷するためにも同様の答えがあります。

ラインを印刷したいのでいいえawk一致すると、file2の列2に含まれる行を印刷するコマンドを作成できます。いいえfile1を参照してください。

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

terdonでも同様に説明したように上記の質問

  • NR==FNR:NRは現在の入力ライン番号、FNRは現在のファイルのライン番号です。両方のファイルは、最初のファイルを読み取る場合にのみ同じです。
  • c[$2]++; next:最初のファイルの場合は、2番目のフィールドをc配列として保存します。次に、最初のファイルにのみ適用されるように、次の行に移動します。
  • c[$2] == 0:elseブロックはこれが2番目のファイルの場合にのみ実行されるため、そのファイルのフィールド2がすでに表示されていることを確認し(c[$2]==0)、その場合はその行を印刷します。のデフォルトのawkジョブは行を印刷することであるため、c[$2]==0trueの場合は行が印刷されます。

しかし、列2がfile2の行と一致しないfile1の行も必要です。同じコマンドで場所を簡単に変更することでこれを実現できます。

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

これで2回使用して目的の出力を生成できますawk。おそらく、より多くの専門知識を持つ人がawk一度に行うことができます。

質問にタグを付けた/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

答え2

私はdiffが(カットと組み合わせても)これを処理するのに十分柔軟ではないと思います。実際に望むのはfile2にないfile1のキーであり、その逆の場合も同様です。厳密に言えば、一行ずつ差があるわけではありません。入力ファイルが大きい場合は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

次の方法で一度に作業を実行できます。

$ awk '{t[$2]=t[$2]$0"\n";NR==FNR?a[$2]=1:b[$2]=1}END{for(i in t)if(a[i]!=b[i])printf"%s",t[i]}' file1 file2
Another   193 stuff2
Something  456 item2
Something  768 item3
Another   783 stuff3

説明する:

  • 各行に対して、次の操作を行います。
    • {t[$2]=t[$2]$0"\n";tそのキーで索引付けされた表で、同じキーを持つすべての行を結合します。
    • NR==FNR?a[$2]=1:b[$2]=1}キーが最初のファイルにある場合はaテーブルに入れ、それ以外の場合b
  • END最後に:
    • {for(i in t)表の各キーに対して、次の操作を行いますt
      • if(a[i]!=b[i])キーが1つのファイルにのみ存在する場合:
        • printf"%s",t[i]}すべての行を印刷するには、このキーを使用します。

これは、キーが重複している場合(キーなしで他のファイルのすべての行を印刷する場合)でも機能しますが、行の順序は保持されません(行はキーごとにアルファベット順に印刷されます)。

関連情報