これがawkの設計目的です。
$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|
説明
-F'|'
:フィールドセパレーターをに設定します|
。
NR==FNR
:NRは現在の入力行番号で、FNRは現在のファイルの行番号です。2つは、最初のファイルが読み取られている間のみ等しくなります。
c[$1$2]++; next
:これが最初のファイルの場合、c
配列の最初の2つのフィールドを保存します。次に、次の行にスキップして、これが最初のファイルにのみ適用されるようにします。
c[$1$2]>0
:elseブロックは、これが2番目のファイルである場合にのみ実行されるため、このファイルのフィールド1と2がすでに表示されているかどうかを確認し(c[$1$2]>0
)、表示されている場合は行を出力します。ではawk
、デフォルトのアクションは行を印刷するため、c[$1$2]>0
trueの場合、行が印刷されます。
あるいは、Perlでタグ付けしたため:
perl -e 'open(A, "file2"); while(<A>){/.+?\|[^|]+/ && $k{$&}++};
while(<>){/.+?\|[^|]+/ && do{print if defined($k{$&})}}' file1
説明
最初の行が開きfile2
、2番目までのすべて|
(.+?\|[^|]+
)を読み取り$&
、それを最後の一致演算子の結果である%k
ハッシュに保存します。
2行目はfile1を処理し、同じ正規表現を使用して最初の2列を抽出し、それらの列が%k
ハッシュで定義されている場合は行を出力します。
上記のアプローチは両方とも、file2の最初の2列をメモリに保持する必要があります。数十万行しかない場合は問題になりませんが、そうであれば、次のようなことができます。
cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done
しかし、それは遅くなります。