Estou tentando encontrar o primeiro byte diferente de zero (começando em um deslocamento opcional) em um dispositivo de bloco usando dd
e imprimindo seu deslocamento, mas estou preso. Não mencionei dd
no título porque imaginei que poderia haver uma ferramenta mais apropriada do que dd
fazer isso, mas achei que dd
deveria ser um bom começo. Se você conhece uma ferramenta mais adequada e/ou mais eficiente para atingir meu objetivo, tudo bem também.
Enquanto isso, mostrarei até onde cheguei dd
no bash até agora.
#!/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
Como você pode ver, estou preso a dois problemas que não sei como resolver:
a. Como faço o while
loop break
quando dd
chega ao final do arquivo/dispositivo? dd
fornece um código de saída de 0
, onde eu esperava um código de saída diferente de zero.
b. Como avalio se o byte que dd
lê e retorna no stdout é diferente de zero? Acho que li em algum lugar que cuidado especial \0
também deve ser tomado no bash com bytes, mas nem tenho certeza se isso se aplica a essa situação.
Você pode me dar algumas dicas sobre como proceder ou talvez sugerir uma forma alternativa de atingir meu objetivo?
Responder1
Você pode fazer isso usandocmp
, comparando à /dev/zero
:
cmp /path/to/block-device /dev/zero
cmp
fornecerá o deslocamento do primeiro byte diferente de zero.
Se quiser pular bytes, você pode usar a opção cmp
do GNU -i
, ou se não estiver usando o GNU cmp
, alimente-o com os dados apropriados usando dd
:
cmp -i 100 /path/to/block-device /dev/zero
dd if=/path/to/block-device bs=1 skip=100 | cmp - /dev/zero
Isso funcionará com qualquer arquivo, não apenas com dispositivos de bloqueio.
Responder2
A resposta de Stephen Kitttorna isso um pouco inútil (é mais conciso e mais de uma ordem de magnitude mais rápido), mas uma alternativa que você tem é despejar (hex) o conteúdo do seu dispositivo, um byte por linha, e canalizá-lo para um programa que imprime o endereço do primeiro byte cuja representação não é 00
e sai assim que o encontra:
od -Ad -w1 -tx1 /dev/device | awk '$2 && $2 != "00" { print $1 + 1; exit }'
od
A -j
opção permite selecionar opcionalmente o número de bytes a serem ignorados (no início da entrada).
Uma variação muito mais rápida (graças aPedro Cordes' comentários) requer um pouco mais de digitação:
od -Ad -tx1 | awk '
{
for (i=2; i<=NF; i++)
if ($i != "00") {
print ($1 + i -1)
exit
}
}'
Permitir od
a saída de dados em seu formato preferido requer calcular o deslocamento do primeiro byte diferente de zero adicionando sua posição na linha em que aparece ao endereço da linha.