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