web-dev-qa-db-ja.com

ファイル内のゼロの大きなストレッチを見つける簡単な方法

最近、2.5TBの障害のあるディスクを部分的に回復しました。 ddrescueは、ループバックモードでマウントできるイメージを作成しました。2.1TBが回復し、450GBが欠落していますが、残念ながらディスク全体に広がっています。

影響を受けるファイルを確認するには、filefrag -vを使用して、ddrescueによって生成されたマップファイルを確認します。

しかし、それには時間がかかります。回復しているのはビデオファイルのみであるため、ゼロの大きなストレッチは予想されませんが、ddrescueがディスクからデータを読み取らなかった場所に存在することがわかりました。

したがって、ファイルにすべてゼロの(任意の)大きなパッチがある場合は、ファイルをスキャンするコマンドが必要になります。実際には、これらは常に512バイトの倍数であり、常に512バイトのアドレスで始まります。そのようなバイナリバイトシーケンス(つまり、512× '\ 0')についてファイルをスキャンできるコマンドはありますか?

4
Ro-ee

xenoidの回答 を変更して具体的にnullバイトを探します この他の質問の回答 = nullバイトをgrepする方法について:

grep -Pal '\x00{512}' the_files
4
MJ713

別のアプローチ、したがって私からの別の答え。

ddrescue自体を使用して、ゼロを検索できます。 --generate-modeを使用します。

ddrescue--generate-modeオプションで呼び出されると、デフォルトの「レスキューモード」とは異なる「生成モード」で動作します。つまり、--generate-modeオプションを使用した場合、ddrescueは何もレスキューしません。後で使用するためにmapfileを生成しようとするだけです。

[…]

ddrescueは、場合によっては、mapfileinfileの(部分的な)コピーからおおよそのoutfileを生成できます。これは、正確なmapfileとほぼ同じです。これは、すべてゼロを含むセクターがレスキューされなかったと単純に想定することで実現されます。

[…]

ddrescue --generate-mode infile outfile mapfile

ソース

ファイルが前回のoutfile実行からのddrescueであると仮定しましょう。 infileとして使用することはできません(ddrescueinfileが同じファイルの場合、outfileは機能しないため)、ダミーのファイルが必要です。/dev/zeroで十分です。すべてのゼロを見つけるには、-b 1が必要です。これはコマンドです(mapfileは存在してはなりません):

ddrescue -b 1 --generate-mode /dev/zero file mapfile

mapfile内のデータブロックのリストに?が含まれるすべてのエントリは、ゼロのブロックを意味します(-b 1の場合、1つのゼロもブロックです)。 ddrescueのマップファイル構造 を参照してください。その後、mapfileから情報を取得できます。

たとえば、次のコマンドは、ゼロの最大ブロックの長さ(16進数、-b 1のためにバイト単位)を示します(空の出力は、何もなかったことを意味します)。

grep '0x.*0x.*[?]' mapfile | awk -F ' ' '{print $2}' | sort -ru | head -n 1

速度を上げるには、より大きなブロックサイズ(-b)を使用することをお勧めしますが、あるブロック内で始まり、次のブロック内で終わるゼロのブロックは、選択したブロックサイズよりわずかに長くても、気付かない場合があります。それらのオフセットが重要になります。

長さがNバイト以上のゼロのストレッチを見逃さないようにするには、最大M=$(((N+1)/2))バイトのブロックサイズが必要です(たとえば、5の場合は最大N=106の場合はN=11)。コマンド

ddrescue -b "$M" --generate-mode /dev/zero file mapfile

データブロックのリストに?が含まれるすべての行が少なくともMゼロ(右側のオフセット)を意味するマップファイルを生成しますが、Nゼロのすべてのストレッチ(オフセットに関係なく)は確実にそのような行を生成します。 Mの2つのブロックは少なくともNであるため、次の理由が当てはまります。

データブロックのリストから?の行を取得し、

  • 長さ(mapfileの2番目の列、単位はMであることを忘れないでください)が0x2以上の場合、この位置にはN以上のゼロがあります。
  • 長さが0x1の場合、この位置の周囲に少なくともNゼロがあるかどうかをさらに調査する必要があります。
  • そのような行がない場合は、ファイルにNゼロのストレッチはありません。

実際には、これらは常に512バイトの倍数であり、常に512バイトのアドレスで始まります。

この場合

ddrescue -b 512 --generate-mode /dev/zero file mapfile

それらすべてを見つけてマッピングします。

2

grepにnull文字を明示的に検索させると、私にはわかりません。ただし、512個の連続する同一の文字(ほとんどありそうもない)を検索するようにするのは、いくぶん簡単です。

grep -Eal '(.)\1{511}' the_files

512個の同一文字のシーケンスが見つかったファイルをリストします。 -aパラメーターは、ヌル文字と一致させるために必要です(そうでない場合、行末文字と見なされ、無視されます)。

2
xenoid

xenoidの答え 影響を受けるファイルをすばやく見つけることができます。さらに確認して分析するには、次のコマンドを実行します。

<"file" tr '\000-\377' 'oL' | fold -w 512 | grep -vn 'L' | cut -f 1 -d ':'

これは次のように機能します。

  1. "file"が開かれ、最初のコマンドにストリーミングされます。
  2. trはすべてのヌル文字をoに変換し、すべての非ヌル文字はLに変換します。
  3. foldは、512文字ごとに改行を挿入します。現時点では、ストリームは純粋なテキストとして扱うことができます。
  4. grepは、Lを含まない行を取り、それらの番号を出力します。
  5. cutはこれらの番号を分離します(ooo…を削除します)。

このようにして、ゼロで満たされた512バイトのチャンクの序数を取得します。番号付けは1で始まります。出力をwc -lに渡して、特定のファイルで影響を受けるチャンクの数を確認します。

2

これは時々欲しかったものなので、興味をそそられました。少し検索して、 this Python 3 program

ページの下部でwgetコマンドを実行しましたが、完全に機能します(ただし、権限によってはSudoが必要になる場合があります)。 grepと同様に、正規表現検索を含む多くの強力なオプションがあります。ヘッダーの例はそれらのいくつかを示しています。 bgrep --helpは完全なリストを提供します。

使用するには、512個のダブルゼロを含む実行文字列が必要になります。入力せずに、次のようなものを使用してください。

bgrep -l $(for f in {0..511}; do echo -n 00; done) files...

-rオプションを使用して、完全なディレクトリツリーをトラバースすることをお勧めします。

私はこの答えを追加しました。他の人が不十分であるためではなく(Kamil Maciorowskiのコマンドシーケンスの創意工夫が特に好きでした)、この質問に遭遇する関連する問題を持つ他の人(私のような)にとって価値があるかもしれないからです。

1
AFH