Wie finde ich mit einem optionalen Offset das erste Byte ungleich Null auf einem Blockgerät?

Wie finde ich mit einem optionalen Offset das erste Byte ungleich Null auf einem Blockgerät?

Ich versuche, das erste Byte ungleich Null (beginnend bei einem optionalen Offset) auf einem Blockgerät zu finden ddund seinen Offset auszudrucken, aber ich stecke fest. Ich habe es ddim Titel nicht erwähnt, da ich dachte, es könnte ein geeigneteres Tool dddafür geben, aber ich dachte, dddas 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 ddbisher 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 whileSchleife break, die dddas Ende der Datei/des Geräts erreicht hat? ddgibt einen Exit-Code von aus 0, wo ich stattdessen einen Exit-Code ungleich Null erwartet habe.
b. Wie bewerte ich, ob das Byte, das ddgelesen 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

cmpgibt Ihnen den Offset des ersten Bytes ungleich Null.

Wenn Sie Bytes überspringen möchten, können Sie die Option cmpvon GNU verwenden -ioder, 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, 00und beendet wird, sobald es dieses findet:

od -Ad -w1 -tx1 /dev/device | awk '$2 && $2 != "00" { print $1 + 1; exit }'

odMit der -jOption 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.

verwandte Informationen