ddの効率的な使用(複数のチャンクをバッファリングし、一度に1つずつ処理)

ddの効率的な使用(複数のチャンクをバッファリングし、一度に1つずつ処理)

$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各セクタオフセットに対して実行することができ、見つかった最初の違いで終了しますcmpcmp各部門に電話してみてください。

grep -aboORを使用して可能なバイトオフセット候補を見つけることもできますが、strings -t dこれは探している実際のパターンによって異なります。これは、数千回の呼び出し(1セクターあたり1つ)ではなく、1つのプログラム呼び出しでコンテンツ全体を検索できるという利点があります。

すべてのタスクを代わりに実行するコマンドラインユーティリティを見つけない限り、要件の完全な内容を一度に検索する小さなC / Go / Pythonスクリプトに勝つことはできません。

あなたのスクリプトのアイデアももちろんうまくいきますが、これはddループ内で再度呼び出して一度に1ブロックずつstdinを読み取ることを意味し、これはおそらく以前より遅くなります。read

答え2

このsplitコマンドを使用して、ファイル内の隣接するチャンクに対して「フィルタ」を実行し、を使用してフィルタを作成できますcmp。その後、成功した一致ごとに改行文字を取得し、その一致を計算するために使用されます。たとえば、ファイル、テンプレートブロックファイル、およびテンプレートブロックのサイズの場合は、次のコマンドラインのようになります。echotruewc$F$TB$SZ

$ split -b $SZ --filter="cmp $TB >& /dev/null && echo ; true" $F | wc -l

これtrueにより、フィルタコマンドラインの成功が保証され、入力を節約するために代わりに使用できます。:ただし、読みやすさは向上しません。

cmpまた、戻りコードだけに興味があるので、すべての出力(stdoutやstderrなど)のリダイレクトに注意してください。

関連情報