
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 ein
und 800950+0 Datensätze aus
? Nach der Warnung ist es +1. Ist das ein Fehlerzähler?
Antwort1
Zusammenfassung: dd
ist ein launisches Tool, das sich nur schwer richtig verwenden lässt. Verwenden Sie es nicht, auch wenn Ihnen die zahlreichen Tutorials das empfehlen. dd
hat 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.
dd
führt einen einzelnen Aufruf des read
Systemaufrufs pro Block durch (definiert durch den Wert von bs
). Es gibt keine Garantie, dass der read
Systemaufruf 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 read
Systemaufruf weniger als einen vollständigen Block zurückgibt, dd
wird 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 dd
ein unvollständiger Block übertragen. In den Blockzählungen +1
bedeutet , 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 dd
sind Bytes, aus denen gelesen wurde /dev/urandom
. Sie haben jedoch weniger Bytes als erwartet erhalten.
Linux /dev/urandom
kommt mit beliebig großen Anfragen zurecht (Quelle:extract_entropy_user
in drivers/char/random.c
), dd
ist also normalerweise beim Lesen sicher. Das Lesen großer Datenmengen braucht jedoch Zeit. Wenn der Prozess ein Signal empfängt, kehrt der read
Systemaufruf zurück, bevor sein Ausgabepuffer gefüllt ist. Dies ist ein normales Verhalten, und Anwendungen sollten read
in einer Schleife aufrufen; dd
tut dies aus historischen Gründen nicht ( dd
die 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 dd
Prozess ein Signal, das den Lesevorgang unterbricht. Sie haben die Wahl, entweder zu wissen, wie viele Bytes dd
insgesamt kopiert werden (stellen Sie sicher, dass Sie ihn nicht unterbrechen – keine Fortschrittskontrolle, keine Unterbrechung) oder zu wissen, wie viele Bytes dd
bisher kopiert wurden, in welchem Fall Sie nicht wissen können, wie viele Bytes noch kopiert werden.
Die Version vondd
in GNU Coreutils(wie man es unter nicht eingebettetem Linux und unter Cygwin findet) hat ein Flag fullblock
, das anweist, in einer Schleife dd
aufzurufen (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).read
write
dd
dd if=/dev/urandom iflag=fullblock of=file bs=1M count=1000000
Eine andere Möglichkeit, um sicherzugehen, was dd
passiert, 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 read
vor 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 dd
istverwende nichtdd
. Obwohl dd
es 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/…
), dd
ist 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 dd
mit einer großen Blockgröße und festgestellt head
.
Wenn Sie am Anfang einige Bytes überspringen müssen, führen Sie eine Pipe tail
in 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 lsof
den 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 anrufenpv
um einen Fortschrittsbericht zu erhalten (besser als dd
der von ), auf Kosten eines zusätzlichen Elements in der Pipeline (leistungsmäßig ist dies kaum wahrnehmbar).
Antwort2
Die Warnung wird angezeigt, wenn dd
nicht 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 dd
ein 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 count
erhalten Sie nicht die gewünschte Datenmenge. Aufgrund von Teillesevorgängen of
wird kleiner sein als count*bs
am Ende.
Wenn Sie also verwenden count
, sollten Sie technisch gesehen immer iflag=fullblock
auch verwenden.
Dies +x
sollte 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.