
各行が一意の識別子で始まるファイルがあります。たとえば、次のようになります。
$ cat source.txt
aaa text
bbb text
ccc text
ddd text
eee text
-fオプションと一緒にfgrepを使用して、別のファイル(「list.txt」と呼ばれる)にリストされている識別子を含む行を新しいファイルに保存してみました。
fgrep -f list.txt source.txt > new.txt
問題は、「list.txt」の一部の識別子が重複していることです。例:
$ cat list.txt
aaa
ccc
ccc
ccc
eee
eee
ここで grep は、繰り返される各識別子を一度だけリストされたように処理し、次のような結果を提供します。
$ cat new.txt
aaa text
ccc text
eee text
代わりに、繰り返し識別子を含む行をその識別子が繰り返される正確な回数でlist.fileに保存したいと思います。この場合、より良い最終結果は次のとおりです。
$ cat new.txt
aaa text
ccc text
ccc text
ccc text
eee text
eee text
grepが重複した識別子を一度だけリストされているように処理しないように強制する簡単な方法はありますか?または、awkを使用するなど、grepなしで目的の結果を得るための別の方法はありますか?
問題をよりよく視覚化するために、source.txtの実際の行は次のとおりです。
head -n 1 source.txt | cat -T
GCF_000005825.2_WP_003320558.1 MULTISPECIES: IS21-like element helper ATPase IstB [Bacillaceae]^IMNEQIQAYAKRLKLSWIRENFNQIEAETNEEYLLKLFEKEVQNREERKVNLLLSQAQLPKTGSTPFQWEHIQIPQGIERTAVINGDFIKERENLILYGGVGTGKTYLATLLSLNAIHRFGSQVKFYTVAGLVNKLIEANQKNTLPKLMKQIEKLDLLILDELGYIPLNKEGAELLFQVISMCYENRSIVITTNLQFGQWNHVFGDPILTEAVIDRLIHHSHLLVFKGDSFRYKESLLHQ
一致する識別子は次のとおりです。
GCF_000005825.2_WP_003320558.1
答え1
これを行う1つの方法は次のとおりですawk
(source.txt
メモリの問題が発生するほど大きくないと仮定します)。
$ awk 'NR==FNR{a[$1]=$0; next} $0 in a{print a[$0]}' source.txt list.txt
aaa text
ccc text
ccc text
ccc text
eee text
eee text
NR==FNR{a[$1]=$0; next}
次に、最初のフィールドをキーにし、入力行全体を値として配列を作成します(source.txt
この場合は最初のファイルの場合)。$0 in a{print a[$0]}
list.txt
ファイルを処理するときは、各行が配列のキーとして存在することを確認し、その行をa
印刷します。
以下は、メモリ側でより良いパフォーマンスを発揮する修正されたソリューションです(行にsource.txt
単一のスペースで区切られた2つのフィールドがあると仮定)。
awk 'NR==FNR{a[$1]=$2; next} $0 in a{print $0, a[$0]}'
行全体ではなく、2番目のフィールドのみが配列に格納されます。印刷したら、キーの前に貼ります。
答え2
xargs
重い負荷を積むもう一つの方法 。
$ grep -v "^$" list.txt | xargs -I{} grep "^{} " source.txt
aaa text
ccc text
ccc text
ccc text
eee text
eee text
$