Estoy tratando de encontrar el primer byte distinto de cero (a partir de un desplazamiento opcional) en un dispositivo de bloque usando dd
e imprimir su desplazamiento, pero estoy atascado. No lo mencioné dd
en el título porque pensé que podría haber una herramienta más apropiada que dd
hacer esto, pero pensé dd
que debería ser un buen comienzo. Si conoce una herramienta más adecuada y/o una forma más eficiente de alcanzar mi objetivo, también está bien.
Mientras tanto, les mostraré hasta dónde he llegado dd
en bash hasta ahora.
#!/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 puedes ver, tengo dos problemas que no sé cómo resolver:
a. ¿Cómo hago el while
bucle break
cuando dd
he llegado al final del archivo/dispositivo? dd
proporciona un código de salida de 0
, donde esperaba un código de salida distinto de cero.
b. ¿Cómo evalúo si el byte que dd
se lee y devuelve en la salida estándar no es cero? Creo que leí en alguna parte que \0
también se debe tener especial cuidado en bash con los bytes, pero ni siquiera estoy seguro de que esto se relacione con esta situación.
¿Puede darme algunas sugerencias sobre cómo proceder, o quizás sugerirme una forma alternativa de lograr mi objetivo?
Respuesta1
Puedes hacer esto usandocmp
, comparado a /dev/zero
:
cmp /path/to/block-device /dev/zero
cmp
le dará el desplazamiento del primer byte distinto de cero.
Si desea omitir bytes, puede usar la opción cmp
de GNU -i
, o si no está usando GNU cmp
, proporcione los datos apropiados usando dd
:
cmp -i 100 /path/to/block-device /dev/zero
dd if=/path/to/block-device bs=1 skip=100 | cmp - /dev/zero
Esto funcionará con cualquier archivo, no solo con dispositivos de bloqueo.
Respuesta2
La respuesta de Stephen Kitt.hace que esto sea un poco inútil (es más conciso y más de un orden de magnitud más rápido), pero una alternativa que tiene es volcar (hexadecimalmente) el contenido de su dispositivo, un byte por línea, y canalizarlo a un programa que imprima la dirección del primer byte cuya representación no lo es 00
y sale tan pronto como lo encuentra:
od -Ad -w1 -tx1 /dev/device | awk '$2 && $2 != "00" { print $1 + 1; exit }'
od
La opción de -j
le permite seleccionar opcionalmente el número de bytes a omitir (al comienzo de la entrada).
Una variación mucho más rápida (gracias aPedro Cordes'comentarios) requiere un poco más de escritura:
od -Ad -tx1 | awk '
{
for (i=2; i<=NF; i++)
if ($i != "00") {
print ($1 + i -1)
exit
}
}'
Permitir od
generar datos en su formato preferido requiere calcular el desplazamiento del primer byte distinto de cero agregando su posición en la línea en la que aparece a la dirección de la línea.