オプションのオフセットを使用して、ブロック デバイス上の最初のゼロ以外のバイトを見つけるにはどうすればよいですか?

オプションのオフセットを使用して、ブロック デバイス上の最初のゼロ以外のバイトを見つけるにはどうすればよいですか?

ブロック デバイス上の最初のゼロ以外のバイト (オプションのオフセットから始まる) を見つけて、ddそのオフセットを印刷しようとしていますが、行き詰まっています。ddタイトルでは言及しませんでしたが、ddこれを行うよりも適切なツールがあるかもしれないと思ったのですが、dd良いスタートになると思いました。私の目的を達成するためのより適切なツールやより効率的な方法をご存知でしたら、それも結構です。

その間、私がddこれまでに bash でどの程度進歩したかをお見せします。

#!/bin/bash

# infile is just a temporary test file for now, which will be replaced with /dev/sdb, for instance
infile=test.txt
offset=0

while true; do
  byte=`dd status='none' bs=1 count=1 if="$infile" skip=$offset`
  ret=$?

  # the following doesn't appear to work
  # ret is always 0, even when the end of file/device is reached
  # how do I correctly determine if dd has reached the end of file/device?
  if [ $ret -gt 0 ]; then
    echo 'error, or end of file reached'
    break
  fi

  # I don't know how to correctly determine if the byte is non-zero
  # how do I determine if the read byte is non-zero?
  if [ $byte ???? ]; then
    echo "non-zero byte found at $offset"
    break
  fi

  ((++offset))
done


ご覧のとおり、解決方法がわからない問題が 2 つあります。a
. がファイル/デバイスの末尾に到達したときにwhileループを作成するにはどうすればよいでしょうか。 は終了コード を返しますが、代わりに非ゼロの終了コードが返されることを期待していました。b . 読み取られて stdout に返されるバイトが非ゼロかどうかを評価するにはどうすればよいですか。どこかで、bash でもバイトに対して特別な注意を払う必要があると読んだことがあると思いますが、これがこの状況に当てはまるかどうかさえわかりません。breakdddd0
dd\0

どのように進めればよいか、あるいは目標を達成するための別の方法を提案していただけますか?

答え1

これは次のようにして行うことができますcmpと比較すると/dev/zero

cmp /path/to/block-device /dev/zero

cmp最初のゼロ以外のバイトのオフセットを返します。

バイトをスキップしたい場合は、GNUcmp-iオプションを使用できます。GNU を使用していない場合はcmp、次のように適切なデータを入力しますdd

cmp -i 100 /path/to/block-device /dev/zero
dd if=/path/to/block-device bs=1 skip=100 | cmp - /dev/zero

これは、ブロックデバイスだけでなく、任意のファイルで機能します。

答え2

スティーブン・キットの回答これは少し無意味になります (より簡潔で、桁違いに高速です)。ただし、別の方法として、デバイスの内容を 1 行に 1 バイトずつ (16 進数で) ダンプし、表現が一致しない最初のバイトのアドレスを出力して00、見つかったらすぐに終了するプログラムにパイプする方法があります。

od -Ad -w1 -tx1 /dev/device | awk '$2 && $2 != "00" { print $1 + 1; exit }'

odオプションを-j使用すると、スキップするバイト数をオプションで選択できます(入力の先頭)。

はるかに高速なバリエーション(ピーター・コーデス' コメント) には、もう少し入力が必要です。

od -Ad -tx1 | awk '
  {
    for (i=2; i<=NF; i++)
      if ($i != "00") {
        print ($1 + i -1)
        exit
      }
  }'

データを優先形式で出力できるようにするには、odそのデータが現れる行内の位置を行のアドレスに追加して、最初のゼロ以外のバイトのオフセットを計算する必要があります。

関連情報