400GBのバイナリファイルをgrepする最速の方法は何ですか? HDDダンプでtxtファイルが必要で、そのファイルの一部の文字列を知っていて、ダンプでファイルを探したいと思います。
私は試してみましたが、grep -a -C 10 searchstring
grepが改行なしで大きなデータの塊を読み取ろうとすると、メモリ不足が原因でクラッシュします。そして、最初から検索を開始するのではなく、ファイルの特定のポイントから検索を開始すると思いました。
答え1
私はこれをこのように使用しますstrings
:
strings 400Gfile.bin | grep -C 10 searchstring
与えられたオフセット(例えば20G)から始めるには、
dd if=400Gfile.bin bs=20G skip=1 | strings | grep -C 10 searchstring
答え2
bgrep
時々私はこのランダムリポジトリに戻ります。https://github.com/tmbinc/bgrep
Readme "インストール"によると:
curl -L 'https://github.com/tmbinc/bgrep/raw/master/bgrep.c' | gcc -O2 -x c -o $HOME/.local/bin/bgrep -
最小例の使用例:
printf '\x01\x02abcdabcd' > myfile.bin
bgrep -B2 -A2 6263 myfile.bin
出力:
myfile.bin: 00000003
\x02abc
myfile.bin: 00000007
dabc
6263
これはASCII形式bc
で、2バイトのシーケンスが0インデックス位置3と7で一致するためです。
SSDでテストしたLnovo ThinkPad P51の32GBメモリに収まらない大容量ファイルを処理できるかどうかを見てみましょう。
dd count=100M if=/dev/zero of=myfile.bin
printf '\x01\x02abcdabcd' >> myfile.bin
time bgrep -B2 -A2 6263 myfile.bin
出力:
myfile.bin: c80000003
\x02abc
myfile.bin: c80000007
dabc
real 11m26.898s
user 1m32.763s
sys 9m53.756s
それで時間がかかりましたが効果がありました。
やや面倒なのは、プレーンテキスト文字を直接検索する機能がサポートされていないことです。 16進文字列を指定する必要があります。しかし、我々はベースにすることができますhttps://stackoverflow.com/questions/2614764/how-to-create-a-hex-dump-of-file- Contains-only-the-hex-characters-without-spac
bgrep `printf %s bc | od -t x1 -An -v | tr -d '\n '` myfile.bin
したがって、Bash エイリアスが役に立ちます。
bgrepa() {
pat=$1
shift
bgrep `printf %s "$pat" | od -t x1 -An -v | tr -d '\n '` "$@"
}
bgrepa bc -B2 -A2 myfile.bin
正規表現はサポートされていません。
Ubuntu 23.04、bgrep 28029c9203d54f4fc9332d094927cd82154331f2でテストされました。
答え3
grepの問題は、メモリにフルラインが必要であることです。行が大きすぎてメモリに収まらないと、grep爆弾が発生します。このジレンマを解決する唯一の方法は、grepに小さな塊を供給することです。 (これは実際にgrepです。しなければならないとにかくそれ自体でやっていますが、そうではありません。)
dd
開始オフセットを指定するために使用し、使用可能なRAMより大きい行でメモリ不足を防ぐには、またはfold
を使用します。予防するgrep --mmap
grep --mmap
システムブロックは防ぎますが、grep自体のブロックを防ぐこともできません。誰かにテストを受けるのは良いことです。fold
これにより、一定の間隔で改行文字を挿入できます。これは、入力を管理可能な塊に分割するための条件を満たします。
dd if=bigfile skip=xxx | fold | grep -b -a string
これは-b
、ファイル内のテキスト文字列がどこにあるかを知るのに役立つバイトオフセットを提供します。
検索文字列 "Hard"を使用してパフォーマンスを監視するために、別のウィンドウでvmstatを実行して、KVMハイパーバイザーの1つの100 GB論理ボリュームでこれをテストしました。論理ボリュームは、デフォルトでゲストLinux VMがインストールされているハードドライブ(パーティションとファイルシステム)でフォーマットされています。システムのパフォーマンスに影響はありません。各パフォーマンスは約33秒で処理されました(もちろん、これはハードウェアによって大きく異なります)。
速いパフォーマンスが欲しいと言われました。これは、シェルスクリプトでユーティリティを使用するときの最速のパフォーマンスを提供します。より高速な検索を得る唯一の方法は、オフセットを探し、指定されたブロックサイズを読み込み、ブロックをパターンマッチングアルゴリズムに供給し、次のブロックに移動するプログラムをCで書くことです。このタイプの「改善されたgrep」はすでに存在しなければならないようですが、オンラインで検索してみると見つかりません。
答え4
実際にはテキストだが改行文字を持たない巨大なJSONファイル(300Gb - データベースのエクスポート)をgrepする方法を見つけました。問題は、特定のフィールドのバイトオフセットを取得することです。
ugrepを使用して、「tr」を介して手動「行」を解決して作成します。これにより、ファイルはメモリに完全にロードされず、ugrepは「ストリーミング」方式で動作し、ヒット時に結果を印刷し、バイトオフセットは「生」です。たとえば、jsonを断片化するのに便利です。
cat ./full.json | tr '{' '\n' | ugrep --fixed-strings --byte-offset --format='%f:%b:%o%~' --binary --mmap -f ./splitstrings.txt