Как найти первый ненулевой байт на блочном устройстве с необязательным смещением?

Как найти первый ненулевой байт на блочном устройстве с необязательным смещением?

Я пытаюсь найти первый ненулевой байт (начиная с необязательного смещения) на блочном устройстве, используя 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


Как видите, я застрял с двумя проблемами, которые не знаю, как решить:
а. Как мне сделать так, чтобы whileцикл break, когда ddдостиг конца файла/устройства? ddвыдавал код выхода 0, тогда как я ожидал ненулевой код выхода.
б. Как мне оценить, является ли байт, который ddсчитывается и возвращается на stdout, ненулевым? Кажется, я где-то читал, что в bash следует проявлять особую осторожность \0и с байтами, но я даже не уверен, относится ли это к этой ситуации.

Можете ли вы дать мне несколько советов о том, как действовать дальше, или, может быть, предложить альтернативный способ достижения моей цели?

решение1

Вы можете сделать это с помощьюcmp, по сравнению с /dev/zero:

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

cmpдаст вам смещение первого ненулевого байта.

Если вы хотите пропустить байты, вы можете использовать опцию GNU cmp, -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

Ответ Стивена Киттаделает это немного бессмысленным (это более кратко и на порядок быстрее), но у вас есть альтернатива — (шестнадцатеричный) дамп содержимого вашего устройства, по одному байту на строку, и передача его в программу, которая печатает адрес первого байта, представление которого не является , 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вывод данных в предпочтительном формате, необходимо вычислить смещение первого ненулевого байта, добавив его позицию в строке, в которой он находится, к адресу строки.

Связанный контент