Solaris 10を使用しているため、-fを含むgrepオプションが機能しません。
パイプで区切られた2つのファイルがあります。
file1:
abc|123|BNY|Apple|
cab|234|cyx|orange|
def|kumar|pki|bird|
ファイル2:
abc|123|
kumar|pki|
cab|234
File2の最初の2つの列をfile1と比較します(最初の2列でfile1のコンテンツ全体を検索)。次に、ファイル2の2行目などを検索します。
期待される出力:
abc|123|BNY|Apple|
cab|234|cyx|orange|
私が持っているファイルは巨大で、約400,000行を含んでいるので、実行を速くしたいと思います。
これは、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
:これが最初のファイルの場合、最初の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
最初の行はfile2
を開き、2番目の|
(.+?\|[^|]+
)までをすべて読み取り、それを保存します($&
は最後の一致演算子の結果です)。 %k
ハッシュ。
2行目はfile1を処理し、同じ正規表現を使用して最初の2つの列を抽出し、それらの列が%k
ハッシュで定義されている場合は行を出力します。
上記のアプローチはどちらも、file2の最初の2列をメモリに保持する必要があります。数十万行しかない場合は問題になりませんが、もしそうであれば、次のようなことができます。
cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done
しかし、それは遅くなります。
SQLのような方法で問題を考えたい場合は、必ず ' q 'という名前のツールを試してください。
$ q -d '|' "select f1.* from file1 f1 join file2 f2 on (f1.c1 = f2.c1 and f1.c2 = f2.c2)"
SQLクエリに慣れていると、より明確で理解しやすくなります。
おもう
grep -Ff file2 file1
あなたが探しているものです。それは効率的であるべきですが、あなたが望むほど正確であるかどうかはわかりません。 abc|123
(たとえば)が異なる列のfile1
の行にある場合、その行も出力されます。これが絶対に起こらないことを保証できれば、上記の行が機能するはずです。
$ sed 's/^/\^/' 2.txt > temp.txt ; grep 1.txt -f temp.txt
abc|123|BNY|Apple|
cab|234|cyx|orange|