$templateBlock
ファイルが与えられたら、特定のサイズの入力ブロックに一致するブロック数を検索する必要があります$blockSize
。
dd
これを行う効率的な方法は何ですか?以下のメソッドはあまりにもdd
多く呼び出されるので、ひどくて遅いです。
while [ $i -lt $totalBlocks]; do
dd if="$pathToFile" bs=$blockSize count=1 skip=$i | diff $templateBlock -
# Increase $count if $? is 0
# Increase $i by 1
done
最善のアプローチは、おそらく一度に読むすべてをdd
読んで処理する$totalSize
ことです。$blockSize
これにより、一度だけ呼び出すことができますdd
。つまり、dd
すべての(または多くの)チャンクを一度に読み取り、各チャンクを一度に処理できます。これは可能ですか?
たぶん、次のようなものがあります。
dd if="$pathToFile" bs=$blockSize | for-each-block {
diff $templateBlock -
# Update $count if $? is 0
}
理想的にはシェルユーティリティを使いたいです。
つまり、Pythonや同様のプログラムを書く必要はありません。
答え1
シェルスクリプトではGNU diffutilを使用するのが最善ですcmp
。データを比較してオフセットをスキップすることもできるので、--ignore-initial=SKIP1:SKIP2
各セクタオフセットに対して実行することができ、見つかった最初の違いで終了しますcmp
。cmp
各部門に電話してみてください。
grep -abo
ORを使用して可能なバイトオフセット候補を見つけることもできますが、strings -t d
これは探している実際のパターンによって異なります。これは、数千回の呼び出し(1セクターあたり1つ)ではなく、1つのプログラム呼び出しでコンテンツ全体を検索できるという利点があります。
すべてのタスクを代わりに実行するコマンドラインユーティリティを見つけない限り、要件の完全な内容を一度に検索する小さなC / Go / Pythonスクリプトに勝つことはできません。
あなたのスクリプトのアイデアももちろんうまくいきますが、これはdd
ループ内で再度呼び出して一度に1ブロックずつstdinを読み取ることを意味し、これはおそらく以前より遅くなります。read
答え2
このsplit
コマンドを使用して、ファイル内の隣接するチャンクに対して「フィルタ」を実行し、を使用してフィルタを作成できますcmp
。その後、成功した一致ごとに改行文字を取得し、その一致を計算するために使用されます。たとえば、ファイル、テンプレートブロックファイル、およびテンプレートブロックのサイズの場合は、次のコマンドラインのようになります。echo
true
wc
$F
$TB
$SZ
$ split -b $SZ --filter="cmp $TB >& /dev/null && echo ; true" $F | wc -l
これtrue
により、フィルタコマンドラインの成功が保証され、入力を節約するために代わりに使用できます。:
ただし、読みやすさは向上しません。
cmp
また、戻りコードだけに興味があるので、すべての出力(stdoutやstderrなど)のリダイレクトに注意してください。