ファイルの特定の列に対して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]==0
trueの場合は行が印刷されます。
しかし、列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]}
すべての行を印刷するには、このキーを使用します。
これは、キーが重複している場合(キーなしで他のファイルのすべての行を印刷する場合)でも機能しますが、行の順序は保持されません(行はキーごとにアルファベット順に印刷されます)。