Ich versuche, das erste Byte ungleich Null (beginnend bei einem optionalen Offset) auf einem Blockgerät zu finden dd
und seinen Offset auszudrucken, aber ich stecke fest. Ich habe es dd
im Titel nicht erwähnt, da ich dachte, es könnte ein geeigneteres Tool dd
dafür geben, aber ich dachte, dd
das sollte ein guter Anfang sein. Wenn Sie ein geeigneteres Tool und/oder einen effizienteren Weg kennen, um mein Ziel zu erreichen, ist das auch in Ordnung.
In der Zwischenzeit zeige ich Ihnen, wie weit ich dd
bisher mit Bash gekommen bin.
#!/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
Wie Sie sehen, stecke ich bei zwei Problemen fest, bei denen ich keine Lösung weiß:
a. Wie erstelle ich eine while
Schleife break
, die dd
das Ende der Datei/des Geräts erreicht hat? dd
gibt einen Exit-Code von aus 0
, wo ich stattdessen einen Exit-Code ungleich Null erwartet habe.
b. Wie bewerte ich, ob das Byte, das dd
gelesen und auf stdout zurückgegeben wird, ungleich Null ist? Ich glaube, ich habe irgendwo gelesen, dass man in Bash auch bei Bytes besonders vorsichtig sein sollte \0
, aber ich bin mir nicht einmal sicher, ob das auf diese Situation zutrifft.
Können Sie mir einige Hinweise zum weiteren Vorgehen geben oder vielleicht einen alternativen Weg vorschlagen, um mein Ziel zu erreichen?
Antwort1
Sie können dies tun mitcmp
, verglichen mit /dev/zero
:
cmp /path/to/block-device /dev/zero
cmp
gibt Ihnen den Offset des ersten Bytes ungleich Null.
Wenn Sie Bytes überspringen möchten, können Sie die Option cmp
von GNU verwenden -i
oder, wenn Sie GNU nicht verwenden cmp
, die entsprechenden Daten mit folgendem Befehl eingeben dd
:
cmp -i 100 /path/to/block-device /dev/zero
dd if=/path/to/block-device bs=1 skip=100 | cmp - /dev/zero
Dies funktioniert mit jeder Datei, nicht nur mit Blockgeräten.
Antwort2
Stephen Kitts Antwortmacht dies ein wenig sinnlos (es ist prägnanter und um mehr als eine Größenordnung schneller), aber Sie haben eine Alternative dazu, den Inhalt Ihres Geräts (als Hexadezimalwert) zu speichern, ein Byte pro Zeile, und ihn an ein Programm weiterzuleiten, das die Adresse des ersten Bytes ausgibt, dessen Darstellung nicht dies ist, 00
und beendet wird, sobald es dieses findet:
od -Ad -w1 -tx1 /dev/device | awk '$2 && $2 != "00" { print $1 + 1; exit }'
od
Mit der -j
Option können Sie optional die Anzahl der zu überspringenden Bytes auswählen (am Anfang der Eingabe).
Eine viel schnellere Variante (dankPeter Cordes' Kommentare) erfordert etwas mehr Tipparbeit:
od -Ad -tx1 | awk '
{
for (i=2; i<=NF; i++)
if ($i != "00") {
print ($1 + i -1)
exit
}
}'
Um die Datenausgabe im bevorzugten Format zu ermöglichen od
, muss der Offset des ersten Bytes ungleich Null berechnet werden, indem seine Position in der Zeile, in der es erscheint, zur Adresse der Zeile addiert wird.