Erstellen Sie mit dd zufällige Daten und erhalten Sie eine „Warnung wegen teilweisem Lesen“. Sind die Daten nach der Warnung nun wirklich zufällig?

Erstellen Sie mit dd zufällige Daten und erhalten Sie eine „Warnung wegen teilweisem Lesen“. Sind die Daten nach der Warnung nun wirklich zufällig?

Ich erstelle eine 1TB-Datei mit zufälligen Daten mit dd if=/dev/urandom of=file bs=1M count=1000000. Jetzt schaue ich mir kill -SIGUSR1 <PID>den Fortschritt an und erhalte folgendes:

691581+0 Datensätze ein
691580+0 Datensätze aus
725174190080 Bytes (725 GB) kopiert, 86256,9 s, 8,4 MB/s
800950+1 Datensätze ein
800950+0 Datensätze aus
839856947200 Bytes (840 GB) kopiert, 99429,5 s, 8,4 MB/s
dd: warning: partial read (809620 bytes); suggest iflag=fullblock
803432+1 Datensätze ein
803431+1 Datensätze aus
842459273876 Bytes (842 GB) kopiert, 99791,3 s, 8,4 MB/s

Ich kann die Warnung nicht interpretieren. Was steht da? Ist meine Datei nach der Warnung wirklich zufällig oder gibt es ein Problem? Was bedeutet +0 oder +1 in 800950+1 Datensätze einund 800950+0 Datensätze aus? Nach der Warnung ist es +1. Ist das ein Fehlerzähler?

Antwort1

Zusammenfassung: ddist ein launisches Tool, das sich nur schwer richtig verwenden lässt. Verwenden Sie es nicht, auch wenn Ihnen die zahlreichen Tutorials das empfehlen. ddhat den Anschein von „Unix Street Cred“ – aber wenn Sie wirklich verstehen, was Sie tun, wissen Sie, dass Sie es nicht mit der Kneifzange anfassen sollten.

ddführt einen einzelnen Aufruf des readSystemaufrufs pro Block durch (definiert durch den Wert von bs). Es gibt keine Garantie, dass der readSystemaufruf so viele Daten zurückgibt wie die angegebene Puffergröße. Dies funktioniert in der Regel bei normalen Dateien und Blockgeräten, aber nicht bei Pipes und einigen Zeichengeräten. SieheWann ist dd zum Kopieren von Daten geeignet? (oder wann sind read() und write() partiell)für weitere Informationen. Wenn der readSystemaufruf weniger als einen vollständigen Block zurückgibt, ddwird ein Teilblock übertragen. Es wird trotzdem die angegebene Anzahl von Blöcken kopiert, sodass die Gesamtmenge der übertragenen Bytes geringer ist als angefordert.

Die Warnung vor einem „partiellen Lesen“ sagt Ihnen genau dies: Einer der Lesevorgänge war partiell, es wurde also ddein unvollständiger Block übertragen. In den Blockzählungen +1bedeutet , dass ein Block partiell gelesen wurde; da die Ausgabezählung ist +0, wurden alle Blöcke als gelesen ausgegeben.

Dies hat keinen Einfluss auf die Zufälligkeit der Daten: Alle ausgegebenen Bytes ddsind Bytes, aus denen gelesen wurde /dev/urandom. Sie haben jedoch weniger Bytes als erwartet erhalten.

Linux /dev/urandomkommt mit beliebig großen Anfragen zurecht (Quelle:extract_entropy_userin drivers/char/random.c), ddist also normalerweise beim Lesen sicher. Das Lesen großer Datenmengen braucht jedoch Zeit. Wenn der Prozess ein Signal empfängt, kehrt der readSystemaufruf zurück, bevor sein Ausgabepuffer gefüllt ist. Dies ist ein normales Verhalten, und Anwendungen sollten readin einer Schleife aufrufen; ddtut dies aus historischen Gründen nicht ( dddie Ursprünge von sind unklar, aber es scheint als Tool für den Zugriff auf Bänder begonnen zu haben, die besondere Anforderungen haben, und wurde nie als Allzwecktool angepasst). Wenn Sie den Fortschritt prüfen, sendet dies dem ddProzess ein Signal, das den Lesevorgang unterbricht. Sie haben die Wahl, entweder zu wissen, wie viele Bytes ddinsgesamt kopiert werden (stellen Sie sicher, dass Sie ihn nicht unterbrechen – keine Fortschrittskontrolle, keine Unterbrechung) oder zu wissen, wie viele Bytes ddbisher kopiert wurden, in welchem ​​Fall Sie nicht wissen können, wie viele Bytes noch kopiert werden.

Die Version vonddin GNU Coreutils(wie man es unter nicht eingebettetem Linux und unter Cygwin findet) hat ein Flag fullblock, das anweist, in einer Schleife ddaufzurufen (und das Gleiche gilt für ) und so immer ganze Blöcke zu übertragen. Die Fehlermeldung schlägt vor, dass Sie es verwenden; Sie sollten es immer verwenden (sowohl in Eingabe- als auch in Ausgabeflags), außer unter ganz besonderen Umständen (meistens beim Zugriff auf Bänder) – wenn Sie es überhaupt verwenden, das heißt: Es gibt normalerweise bessere Lösungen (siehe unten).readwritedd

dd if=/dev/urandom iflag=fullblock of=file bs=1M count=1000000

Eine andere Möglichkeit, um sicherzugehen, was ddpassiert, ist, eine Blockgröße von 1 zu übergeben. Dann können Sie anhand der Blockanzahl feststellen, wie viele Bytes kopiert wurden. Ich bin mir jedoch nicht sicher, was passiert, wenn a readvor dem Lesen des ersten Bytes unterbrochen wird (was in der Praxis nicht sehr wahrscheinlich ist, aber passieren kann). Aber selbst wenn es funktioniert, ist es sehr langsam.

Der allgemeine Rat zur Verwendung ddistverwende nichtdd. Obwohl ddes oft als Low-Level-Befehl zum Zugriff auf Geräte angepriesen wird, ist es in Wirklichkeit nichts dergleichen: Die ganze Magie geschieht in der Gerätedatei (der /dev/…), ddist nur ein gewöhnliches Tool mit einem hohen Missbrauchspotenzial, das zu Datenverlust führen kann. In den meisten Fällen gibt es einen einfacheren und sichereren Weg, das zu tun, was Sie wollen, zumindest unter Linux.

Um beispielsweise eine bestimmte Anzahl von Bytes am Anfang einer Datei zu lesen, rufen Sie einfach Folgendes auf head:

head -c 1000000m </dev/urandom >file

Ich habe auf meinem Computer einen schnellen Benchmark durchgeführt und keinen Leistungsunterschied zwischen ddmit einer großen Blockgröße und festgestellt head.

Wenn Sie am Anfang einige Bytes überspringen müssen, führen Sie eine Pipe tailin Folgendes durch head:

dd if=input of=output count=C bs=B seek=S
<input tail -c +$((S*B+1)) | head -c $((C*B)) >output

Wenn Sie den Fortschritt sehen möchten, rufen Sie auf, um lsofden Dateioffset anzuzeigen. Dies funktioniert nur bei einer regulären Datei (der Ausgabedatei in Ihrem Beispiel), nicht auf einem Zeichengerät.

lsof -a -p 1234 -d 1
cat /proc/1234/fdinfo/1

Du kannst anrufenpvum einen Fortschrittsbericht zu erhalten (besser als ddder von ), auf Kosten eines zusätzlichen Elements in der Pipeline (leistungsmäßig ist dies kaum wahrnehmbar).

Antwort2

Die Warnung wird angezeigt, wenn ddnicht genügend Daten abgerufen werden konnten, um einen Block in einem einzigen Lesevorgang zu füllen. Dies geschieht bei unregelmäßigen oder langsamen Datenquellen oder bei Quellen, die Daten in kleineren Einheiten als der von Ihnen angeforderten Blockgröße schreiben.

Es gibt kein Problem mit der Datenintegrität, das Problem besteht jedoch darin, dass ddein teilweiser Lesevorgang immer noch als gelesener Block zählt.

Wenn Sie die Option nicht verwenden count, spielt die Warnung kaum eine Rolle, es geht nur um die Leistung. Aber mit counterhalten Sie nicht die gewünschte Datenmenge. Aufgrund von Teillesevorgängen ofwird kleiner sein als count*bsam Ende.

Wenn Sie also verwenden count, sollten Sie technisch gesehen immer iflag=fullblockauch verwenden.

Dies +xsollte die Anzahl der Teilblöcke sein.

Antwort3

< /dev/urandom \
dd ibs=4k obs=64k |
dd bs=64k count=16000000 >file

^Das wird einfach funktionieren. Die Fehlinformation, die sonst hier vorhanden ist, ist offensichtlich falsch. dd's Puffer sindexplizitund so, um Eingaben zu puffernzählenVorkommnisse, die Sie explizit puffern müssen. Das ist alles. Glauben Sie nicht an den Mist.

verwandte Informationen