私はSolaris 10を使用しているので、-fに関連するgrepオプションは機能しません。
パイプで区切られた2つのファイルがあります。
ファイル1:
abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|
ファイル2:
abc|123|
kumar|pki|
cab|234
file2の最初の2つの列をfile1と比較し(最初の2つの列でfile1の内容全体を検索して)、一致する場合は、file1の一致する行を印刷したいと思います。次に、ファイル2の2行目などを検索します。
予想出力:
abc|123|BNY|apple|
cab|234|cyx|orange|
私のファイルは約400,000行を含む大容量なので、実行速度を速くしたいと思います。
答え1
これが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は現在のファイルのライン番号です。両方のファイルは、最初のファイルを読み取る場合にのみ同じです。c[$1$2]++; next
:最初のファイルの場合は、最初の2つのフィールドをc
配列として保存します。次に、最初のファイルにのみ適用されるように、次の行に移動します。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
説明する
最初の行が開き、2行目()file2
までのすべての内容が読み取られ、ハッシュ(最後の一致演算子の結果)に保存されます。|
.+?\|[^|]+
$&
%k
2行目は、同じ正規表現を使用して最初の2つの列を抽出し、その行を印刷する方法でfile1を処理します(その列がハッシュで定義されている場合)%k
。
上記の両方の方法で、file2の最初の2列をメモリに保存する必要があります。問題にならない行は数十万行だけですが、そうであればそうすることができます。
cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done
しかし、速度は遅くなります。
答え2
私の考えでは
grep -Ff file2 file1
これがあなたが探しているものです。うまくいきますが、必要なだけ正確であるかどうかはわかりません。abc|123
たとえば、別の列の行で見つかった場合、そのfile1
行も印刷されます。これが起こらないことを保証できる場合は、上記のコードが機能します。
答え3
SQL用語で考えたい場合は、必ず「」というツールを使ってみてください。キュー':
$ q -d '|' "select f1.* from file1 f1 join file2 f2 on (f1.c1 = f2.c1 and f1.c2 = f2.c2)"
SQLクエリに精通している場合は、より明確で理解しやすくなります。
答え4
$ sed 's/^/\^/' 2.txt > temp.txt ; grep 1.txt -f temp.txt
abc|123|BNY|apple|
cab|234|cyx|orange|