次の詳細を含む3つの大きなファイルがあるシーンがありますTest.txt
。Test1.txt
Test2.txt
H|||||||||||||||||||||||
D||||||||||||||||||||||||
D|||||||||||||||||||||||
H|||||||||||||||||||||
D||||||||||||||||||||||||
D||||||||||||||||||||||||
T||||||||||||||||||||||||
Dラインを除くすべてのアイテムを削除する必要があります。私の3つのファイルすべてでは、次のようになります。 (10GB以上)
D||||||||||||||||||||||||
D|||||||||||||||||||||||
D||||||||||||||||||||||||
D||||||||||||||||||||||||
Test.txt
したがって、 、Test2.txt
、 で D 行だけを保持した後、Test3.txt
新しいファイルにマージする必要があります。
私はsedを使って上記のことをしました。
sed '/^\('D'\)|/!d' $Filename.txt >> $NewFilename.txt
しかし、ファイルが大きいので時間がかかります。
これを効率的に実行するために使用できる他のコマンドはありますか?
答え1
cat Test.txt Test2.txt Test3.txt | LC_ALL=C grep '^D' > newfile.txt
または:
for file in Test.txt Test2.txt Test3.txt; do
LC_ALL=C grep '^D' < "$file"
done > newfile.txt
または、grep
お気に入りのGNUがgrep
その-h
オプションをサポートしている場合(ファイル名の印刷を避けるため):
LC_ALL=C grep -h '^D' Test.txt Test2.txt Test3.txt > newfile.txt
これにより、UTF-8データの解析を回避LC_ALL=C
できます。grep
を使用すると、^D
各行grep
の最初の文字のみが表示されます。grep
、特にgrep
GNUは一般的にsed
。
答え2
これはCPUバインディングではなくI / Oバインディング操作である可能性が高いため、次の正規表現エンジンを使用しなくても次のようになります。
grep -F 'D|' Test.txt Test2.txt Test3.txt
ファイルを線で表示した後にパターンを検索する必要があるため、時間がかかります。
これがワンタイムでエンコーディングを気にしない場合は、mmap(3)
ファイル全体をメモリに入れて次のように使用できますmemmem(3)
。
char *p;
if ((p = memmem(file, size, "\nD|", 3)) != NULL) {
/* massage the line, i.e. find the next '\n'
* and print the region between p+1 and the
* next '\n' */
}
どこにfile
マップされたバッファへのポインタであり、size
ファイルサイズです。 (お手伝いになれば詳しく説明させていただきます。)
このアプローチはまだ時間がかかりますが(問題がI / Oバインドされているため)、少なくともファイルを行として表示する時間を節約できます。