Dd
Achtung dieser Artikel ist noch in Arbeit und dient vorläufig nur als Vorlage. Dieser Beitrag zu Linux oder der Abschnitt ist in Bearbeitung. Weitere Informationen findest du hier. Der Ersteller arbeitet an dem Beitrag oder Abschnitt und entsorgt den Wartungsbaustein spätestens 3 Tage nach der letzten Bearbeitung. Änderungen außer Rechtschreibkorrekturen ohne Absprache mit dem Urspungsautor sind möglichst zu vermeiden, solange dieser Baustein noch innerhalb der genannten Frist aktiviert ist. |
--Robi 19:15, 24. Jun 2007 (CEST)
Inhaltsverzeichnis
das Kommando dd
allgemeines zum Kommando dd
dd ist ein Kommando das noch aus der Urzeit von UNIX stammt. Der Name sollte früher Copy and Convert bedeuten, das Programmkürzel cc war jedoch schon an den C-Compiler vergeben. Daher kam es wohl kurzerhand zu dd. Heute wird dieses Kürzel oftmals als disk dump oder ähnlich übersetzt, ursprünglich sollte es wohl doch mehr an das JCL-Kommando "Data Definition" erinnern, auch die für UNIX-Befehle doch sonderbaren Optionensschreibweisen erinnern noch sehr stark an diese Abstammung.
Das UNIX-Kommando dd dient dem Umleiten von Datenstömen. Dabei kann es diese Datenströme Byteweise bearbeiten und universell blocken. Als Quelle und Ziel der Datenströme können sowohl normale Dateien, die normalen Ein- und Ausgabekanäle der Prozesse und auch Geräteknoten verwendet werden. In früherer Zeit benötigte man das Programm dd , um inkompatible Formate und Zeichensätze zwischen unterschiedlichen Betriebssystemen und Geräten zu kopieren, und um Daten auf externen Peripheriegeräten (oftmals Bandgeräte) lesen und schreiben zu können.
Typischen Beispielaufgaben aus dieser Zeit könnten heute auf Linux etwa so ausgesehen:
- Auslesen eines EBCDIC-Bandes (80 Zeichen pro Record, 10 Records pro Block, Dichte 1600 bpi) Ausgabe als Ascii-Datei:
dd if=/dev/nst1 of=/datei ibs=800 cbs=80 conv=ascii,lcase
Für Konvertierungsaufgaben benötigt man heute dd nur noch wenig. Dort wo noch mit solchen inkompatiblen Daten gearbeitet wird, benutzt man heute meist Programme die schon die entsprechende Ein- und Ausgabefilter mitbringen. Wohl aber benötigt man auch heute noch die universellen Bockungsmöglichkeiten von dd in Bezug auf Datenströme und Geräteknoten sowie die Möglichkeit im Datenstrom gezielt zu positionieren. Besondere "Berühmtheit" hat heutzutage jedoch die Möglichkeit erlangt, Partitionen und ganze Festplatten bytegenau zu kopieren, was fälschlicher Weise dazu verleitet mag dd auch noch in den Rang eines Backuptools zu erheben.
die Optionen von dd
Die Optionen von dd unterscheiden sich grundlegend von denen der meisten UNIX/Linux Kommandos. Eine Übersicht erhaltet ihr mit der Option --help oder der Manpage von dd ( Achtung: evtl. sind nicht alle Optionen in eurer installierten Version vorhanden). Auch eine Infoseite "info:/coreutils/dd invocation" sollte bei vielen installiert sein.
Die genaue SYNOPSIS (ältere Version)
dd [--help] [--version] [if=file] [of=file] [ibs=bytes] [obs=bytes] [bs=bytes] [cbs=bytes] [skip=blocks] [seek=blocks] [count=blocks] [conv={ascii, ebcdic, ibm, block, unblock, lcase, ucase, swab, noerror, notrunc, sync}]
if=Datei |
Der Datenstrom, der umgeleitet werden soll. Das kann eine Datei oder Gerätedatei, also auch eine Festplatte oder ein anderes Gerät sein. Wird if weggelassen liest dd von der Standardeingabe. |
---|---|
of=Datei |
Die Datei, auf die geschrieben werden soll. Dies kann wieder eine Datei oder ein Gerät sein. Wird of weggelassen schreibt dd auf die Standardausgabe. |
ibs=Bytes |
Eingabe-Blockgröße (input block size), gibt an, wie viele Bytes auf ein Mal gelesen werden sollen. |
obs=Bytes |
Ausgabe-Blockgröße (output block size), gibt an, wie viele Bytes auf ein Mal geschrieben werden sollen. |
bs=bytes |
Kurzschreibweise für ibs=bytes obs=bytes. Der Standardwert bei Nichtangabe ist 512 Bytes. |
count=Blocks |
Angabe, um nur eine begrenzte Menge Blöcke zu kopieren. |
skip=Blocks |
Angabe, um eine Anzahl Blocks zu überspringen. |
seek=blocks |
Überspringt diese Anzahl Blöcke beim schreiben auf die Ausgabe. |
conv=Schlüsselwörter |
Wandelt den Datenstrom entsprechend einer Kommagetrennten Liste von Schlüsselwörtern. |
cbs=Bytes |
Umwandlungs-Blockgröße (convert block size): Größe der Blöcke zum Umwandeln auf ein Mal. |
die Ein- und Ausgabefile
Beide Filenamen werden in den Optionen angegeben nach folgenem Prinzip
if=/PATH/EINGABEDATEI #die Datei oder Gerät aus dem gelesen wird of=/PATH/AUSGABEDATEI #die Datei oder Gerät auf das geschrieben wird
sollte einer oder beide nicht explizid so angegeben werden, dann wird von dd automatisch mit dem entsprechenden Standard-Ein/Ausgabe-kanal gearbeitet. Man kann immer jeweils nur einen Dateinamen angeben es geht also weder eine Space- noch Kommaseparierte Kiste und auch die Shell übernimmt hier keine Path- oder Filenamensexpansionen. Nur relative und absolute Dateiadressierung sowie die tilde expansion sind zulässig, ansonsten sind immer komplette Path und Dateinamen anzugeben. Auf den Inhalt von Variablen für die Dateinamen kann zugegriffen werden, soweit im Dateinamen Sonderzeichen enthalten sind muß das aber im dd-Komando unbedingt berücksichtigt werden.
Beispiel:
NULL=/dev/null INFILE="/home/user/datei orginal" dd if="$INFILE" of=$NULL
Achtung: |
Beim Zugriff auf Geräteknoten, also zB Festplatten, Partitionen, Bandgeräte usw. immer einmal mehr prüfen ob nicht doch if und of verwechselt wurden. Es droht hier bei Verwechslungen unter Userkennung root Datenverlust. |
die Blockgröße
Die Blockgröße gibt an, wieviele Byte bei einem read- oder write-Kommando gleichzeitig verarbeitet werden. Im Normalfall ist man unter Linux ja gewohnt, dass man sich darum überhaupt nicht kümmern muss, das macht Linux im Hintergrund für uns immer richtig. Da wird zB von der Tastatur jedes einzelne Zeichen gelesen, Eingaben werden Zeilenweise nach Bestätigung der ENTER-Taste verarbeitet, auf die Festplatte wird mittels des Caches mit 4KB Blockgröße lesend und schreibend zugegriffen, über Internet werden Pakete mit maximaler Größe von 1500 Byte gesendet usw. Alles Dinge von denen wir gar nichts mitbekommen, und von denen wir auch die meisten überhaupt nicht beeinflussen könnten, selbst wenn wir das wollten.
Anders jedoch beim Befehl dd. Hier arbeitet der Befehl, sollten wir nichts anderes angeben, immer mit 512 Byte lesend und schreibend und hier können wir das sowohl beim lesenden- wie auch den schreibenden-Zugriff und sogar getrennt beeinflussen.
Zu was soll das gut sein, werden sich die meisten fragen.
Eine Regentonne voll mit Wasser kann man sowohl mit einem Eimer, mit einer Suppenkelle aber auch mit einem Kaffeelöffelchen leerschaufeln, was ist wohl die schnellste und rückenschonendste Methode? Ähnlich verhalten sich viele Geräte wenn wir direkt zB über dd auf sie zugreifen.
Im folgende Beispiel wird eine kleine Partition einer SCSI-Platte mit "NULLEN" überschrieben, wobei mit der Blockgröße von dd gespielt wird.
time dd if=/dev/zero of=/dev/sdb1 bs=512
(wobei bei bs= die Werte 16 64 512 2K 8K 32K und 128K zum Einsatz kamen)
Blockgröße | real time | user time | sys time |
---|---|---|---|
16 Byte | 2m26.593s | 0m7.898s | 1m2.839s |
64 Byte | 1m39.600s | 0m2.734s | 0m23.812s |
512 Byte | 1m18.710s | 0m0.465s | 0m6.942s |
2 KByte | 1m16.131s | 0m0.100s | 0m3.552s |
8 KByte | 0m29.137s | 0m0.016s | 0m1.299s |
32 KByte | 0m29.159s | 0m0.012s | 0m1.507s |
128 KByte | 0m29.115s | 0m0.003s | 0m1.474s |
Wir erkennen, die default Einstellung von dd (512 Byte) ist zwar auf dieser Platte nicht die Allerschlechteste, aber es geht durchaus noch 3 Mal schneller. Da moderne Festplatten in der Regel heute einen Cache haben der zumindestens beim Lesen genutzt ist, ergeben sich beim Lesen von Partitionen oder ganzen Festplatten oftmals ganz andere (weniger unterschiedliche) Werte.
Wesentlich gravierender sind die Unterschiede jedoch bei Bandlaufwerken, es gibt verschiedene Möglichkeiten wie das Laufwerk die ihm übertragene Blockgröße interpretieren soll, man muss prinzipiell jeden Block mit der selben Blocksize lesen mit der der Block auch geschrieben wurde, eine ungünstige Blockgröße kostet nicht nur Zeit sondern bedeutet auch erhöhten Verschleiß an Bandmaterial und Laufwerk und nicht zuletzt auch noch ein höheres Fehlerrisiko. Wer sich näher damit befassen will oder muss kann unter Bandlaufwerke und Linux und speziell über die richtige Blockgröße bei Bandlaufwerken im Wiki näher infomieren.
Es gibt im Internet die abendteuerlichsten Berechnungsmodelle für die "richtige Blockgröße" von dd für den Zugriff auf Festplatten. Man geht dabei von der Ausgabe des fdisk-Befehles aus, und errechnet aus den dort ausgegebenen Werten der Köpfen, Sektoren, Cylindern und Units irgendwie eine "optimale Blockgröße" und kommt dann auf solche Werte wie zB. 16065 Byte.[1]
Abgesehen, dass solche Werte dann manchmal nicht einmal durch 512 (die kleinste Speichereinheit auf einer Festplatte) teilbar sind, schon eine einfache Überlegung müsste den völligen Unsinn eines solchen Unterfangens aufzeigen.
LINUX:~ # fdisk -l /dev/sdb Disk /dev/sdb: 18.2 GB, 18275768320 bytes 255 heads, 63 sectors/track, 2221 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes .......
Diese Festplatte, die laut Hersteller 5 Scheiben mit je 2 Köpfen hat, sollte jetzt plötzlich 255 Köpfe haben. Damit müsste sie nach heutiger Bauweise in etwa 30 bis 35 cm dick sein und hätte ein stattliches Gewicht von einigen kg. Also absolute Vorsicht mit solchen Berechnungen. Die heutigen Platten verwalten intern ihre eigene Geometrie und werden von außen nur über LBA angesprochen. Die Geometrie die uns zB fdisk nach außen zeigt ist eine reine logische die mit der tatsächlichen nur eines gemein hat, die ungefähre (etwas kleiner) Gesamtgröße, und kann mit Befehlen wie zB. fdisk bei Bedarf auch angepasst oder geändert werden.
Die optimalsten Werte sind von eine Vielzahl von vor allem baulichen Faktoren abhängig und werden heute in vielen Geräten obendrein noch über Cache in den Geräten gepuffert, womit man mit größeren Werten nie falsch liegen kann.
Prinzipiell, (wenn keine anderen Faktoren dagegen sprechen- siehe Positionierung im Datenstrom) nur Werte die durch 512 teilbar sind, für Disketten, kleine Speicherkarten und kleine Sticks und ganz alte oder schon teilweise defekte Platten 512 Byte, für die restlichen Platten 4 oder 8 KByte, bei CD-ROM und DVD 1 oder 2 KByte und für MO-Disk UDO und andere WORM, nur die vom Hersteller und der jeweiligen Technologie vorgeschriebenen Blockgröße, und man sollte auf der richtigen Spur sein.
Positionierung innerhalb des Datenstrom
Als Datenstrom bezeichnen wir hier mal alles, womit dd arbeiten kann, also zB. Pipe, Datei, Gerät,...
DD kennt als Bezugspunkt immer nur den Anfang von Eingangsstrom und Anfang vom Ausgangsstrom. Da man aber nicht immer den kompletten Eingangsstrom bis zum Ende auf Ausgangsstrom von Anfang an kopieren will, muss man innerhalb dieser beide Datenströme auch positionieren können. Das geht mit den Optionen skip= seek= und count= und diese sind jeweils von den gesetzten Blockgrössen abhängig.
Wenn wir dd ohne solche Positionierungs-Optionen starten, dann kopiert dd den Eingangsdatenstrom von Anfang bis ein EOF (End Of File) kommt, komplett auf den Ausgangsdatenstrom. Bei Lese- oder Schreibfehlern wird an dieser Stelle dd abgebrochen. Ein EOF kann das Ende einer normalen File sein, aber auch zB der Abbruch eines am Eingang über Pipe verbundenen Befehles. Auch der Versuch zB. über eine Gerätegrenze (zB Partition zu Ende) zu lesen oder schreiben, führt zu einen EOF Fehler.
Die Gesamtanzahl der zu kopierenden Blöcke kann mit der Option count= begrenzt werden.
count=100
kopiert genau 100 Blöcke ( Eingangsblockgröße )
Es können am Eingangsstrom anfänglich Blöcke (Eingangsblockgröße) übersprungen werden, die dann nicht mit kopiert werden, und die auch nicht von einem eventuell gesetzem count-Wert abgezogen werden. Die Option dazu ist skip=
skip=100 count=50
kopiert genau 50 Blöcke (Eingangsblockgröße) wobei am Anfang 100 (Eingangsblockgröße) übersprungen werden, bevor mit dem kopieren begonnen wird.
Es können am Ausgangsstrom anfänglich Blöcke (Ausgangsblockgröße) übersprungen werden bevor der erste Block dorthin kopiert wird. Diese Option ist seek=.
seek=100 count=50
kopiert die ersten 50 Blöcke (Eingangsblockgröße) vom Eingangstrom ab dem 101 Block (Ausgangsblockgröße) in den Ausgangsstrom. (Die ersten 100 Blocke der Größe obs= bleiben also im Ausgangsstrom unberührt, erst danach kommt der erste kopierte Block) Diese Option macht nicht mit allen Ausgangsdatenströmen Sinn, und führt zB. in Verbindung mit der Standardausgabe zum "hängenbleiben" des Befehles, da ja erstmal auf Daten gewartet werden muss, die gar nicht kommen können. Beim Anwenden auf normale Dateien führt ein zu großer seek-Wert (größer als Ausgangsdatei) zum weiterschreiben der Datei am Ende.
Soweit zur Theorie und zu den wichtigsten Optionen
die Ausgaben von dd
Wir untersuchen dazu einmal exemplarisch eine Ausgabe eines dd-Befehls, hier wurde von der Partition /dev/sda2 mit einer Blockgröße von 8KByte gelesen und auf ein Tape /dev/nst0 mit 256 KByte Blockgröße geschrieben.
LINUX:~ # dd if=/dev/sda2 of=/dev/nst0 ibs=8K obs=256K 262256+0 records in 8195+1 records out 2148401152 bytes (2.1 GB) copied, 74.8721 seconds, 28.7 MB/s
- 262256+0 records in
es wurden 262256 Blöcke a. 8K gelesen, die +0 bedeuten, es gab am Ende keine Rest, also der letzte Block hatte wirklich auch 8K Größe.
- 8195+1 records out
es wurden 8195 Blöcke a. 256K geschrieben, die +1 bedeutet, es wurde zusätzlich noch ein Restbock geschreiben, der nicht die volle Größe von 256K hatte. Wenn mit der Option "bs=" gearbeitet wird, oder die Blockgrößen sonst wie für Ein/Ausgabe gleich sind, dann sollten bei einem ordnungsgemäßen Ablauf des Befehls beide Werte immer gleich ausfallen.
- 2148401152 bytes (2.1 GB) copied, 74.8721 seconds, 28.7 MB/s
die Schlußzeile erhalten wir nur in neueren Versionen von dd. Sie beinhaltet hier die Gesamtanzahl der übertragenen Byte die Zeit und die durchschnittliche Geschwindigkeit.
Solange der Befehl dd läuft erhalten wir ansonsten von ihm keinerlei Ausgaben. Wir können uns aber den Status der aktuell übertragenen Daten in der oben beschriebenen Form anzeigen lassen, wenn wir dem dd-Prozess ein Signal 10 (SIGUSR1) senden. Alle diese Ausgaben kommen über den Standardfehlerausgabekanal des Prozesses dd.
Anwendungsgebiete und Beispiele
mit dd Dateien erzeugen
Hin und wieder benötigt man spezielle Dateien in bestimmter Größe und mit typischen oder speziellen Inhalt. Das können einfach Dateien sein, die man zum testen benötigt oder auch Dateien um darin Filesysteme anzulegen oder oder oder.
Das geht mit dd sehr einfach. Wir benötigen nur einen Quelldatenstrom dazu. Auf die Blockgrößen brauchen wir hier meistens gar nicht zu achten (eventuell/selten könnte aber der gewünschte Quelldatenstrom eine Blockgröße fordern), da das Filesystem in das wir unsere Datei schreiben sowieso gebuffert ist, also können wir mit bs= und count= unsere gewünschte eindeutige Dateigröße sehr schön festlegen.
Blockgröße x Count = Dateigröße
Erzeugen einer mit Nullen gefüllten Datei
Als Quelldatenstrom nutzen wir dazu /dev/zero ( nicht /dev/null , da beim lesen von /dev/null nur ein EOF zurückgeliefert wird und wir eine Datei mit Länge Null erhalten würden)
robi@LINUX:~/test> dd if=/dev/zero of=file.leer bs=1M count=1024 1024+0 Datensätze ein 1024+0 Datensätze aus
erzeugt eine 1GB große (ergibt sich aus 1MByte x 1024) Datei voller Nullen
Erzeugen von Sparse Dateien
robi@LINUX:~/test> dd if=/dev/zero of=file.sparse count=0 obs=1 seek=1G 0+0 Datensätze ein 0+0 Datensätze aus robi@LINUX:~/test> ls -l file.* -rw-r--r-- 1 robi users 1073741824 2007-06-29 23:37 file.leer -rw-r--r-- 1 robi users 1073741824 2007-06-30 01:24 file.sparse -rw-r--r-- 1 robi users 1073741824 2007-06-30 00:12 file.zufall robi@LINUX:~/test> stat file.sparse File: ,,file.sparse" Size: 1073741824 Blocks: 0 IO Block: 4096 reguläre Datei Device: 802h/2050d Inode: 1038268 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1001/ robi) Gid: ( 100/ users) Access: 2007-06-30 01:24:39.168204352 +0200 Modify: 2007-06-30 01:24:39.168204352 +0200 Change: 2007-06-30 01:24:39.168204352 +0200
Schreibt 0 Mal 1 Byte ab Position 1073741824 und erzeugt somit ein 1GB große Sparse Datei Man erkennt es eindeutig an der scheinbaren Differenz zwischen Size und der Anzahl der benutzen Blocks mit stat
Achtung: |
An solchen sparse Dateien ist schon mancher Adim zB bei Backups verzweifelt, man kann ein solches File durch umkopieren mit cp in ein normales Files umwandeln. |
Erzeugen einer Datei gefüllte mit Zufallszahlen
Als Quelldatenstrom nutzen wir dazu unter Linux /dev/urandom (nicht /dev/random , das dauert sonst viel viel zu lange und bringt auch nur das selbe Ergebnis)
robi@LINUX:~/test> dd if=/dev/urandom of=file.zufall bs=1M count=1024 1024+0 Datensätze ein 1024+0 Datensätze aus robi@LINUX:~/test> hexdump -C file.zufall | more 00000000 60 b2 03 a4 f5 13 46 d0 25 a4 f2 09 1c 31 9f 3f |`².€õ.FÐ%€ò..1.?| 00000010 17 b0 8e 32 af a0 87 67 cf 87 2c 4f 6d 92 de 4d |.°.2¯ .gÏ.,Om.ÞM| 00000020 38 3c a2 29 58 09 fd b7 ........ .......
Als Größe wurde hier wieder wie schon oben 1GByte festgelegt. Mit hexdump haben wir gleich mal hineingeschaut, ob auch alles schön zufällig ist. ;-)
Erzeugen einer Datei mit typischen Eigenschaften und genau definierter Länge
Die unterschiedlichen Dateien haben unterschiedliche Eigenschaften zB beim Komprimieren. ZB. Zufallsdateien lassen sich überhaupt nicht komprimieren, Dateien mit lauter Nullen dagegen extrem, Logdateien sehr gut, Textdateien auch noch gut, aber Binärdateien nicht besonders gut. Wenn wir jetzt so eine Datei mit solchen typischen Komprimierungseigenschaften zu Testzwecken benötigen, dann können wir und mit dd eine solche mit genaue definierter Länge erzeugen.
Als Beispiel wollen wir hier eine genau 5MByte große Datei aus einigen Bilddateien erzeugen.
robi@LINUX:~/test> ls -l bild*.jpg -rw-r--r-- 1 robi users 277960 2007-06-29 22:34 bild0.jpg -rw-r--r-- 1 robi users 312872 2007-06-29 22:48 bild10.jpg -rw-r--r-- 1 robi users 120061 2007-06-29 22:08 bild1.jpg -rw-r--r-- 1 robi users 164171 2007-06-29 22:10 bild2.jpg -rw-r--r-- 1 robi users 179737 2007-06-29 22:13 bild3.jpg -rw-r--r-- 1 robi users 173341 2007-06-29 22:13 bild4.jpg -rw-r--r-- 1 robi users 165532 2007-06-29 22:14 bild5.jpg -rw-r--r-- 1 robi users 161892 2007-06-29 22:16 bild6.jpg -rw-r--r-- 1 robi users 126340 2007-06-29 22:17 bild7.jpg -rw-r--r-- 1 robi users 125396 2007-06-29 22:19 bild8.jpg -rw-r--r-- 1 robi users 289134 2007-06-29 22:21 bild9.jpg robi@LINUX:~/test> cat bild*.jpg bild*.jpg bild*.jpg bild*.jpg | dd of=file.bild bs=1024K count=5 5+0 Datensätze ein 5+0 Datensätze aus robi@PLINUX:~/test> ls -l file.bild -rw-r--r-- 1 robi users 5242880 2007-06-30 00:40 file.bild
Unsere Bilddateien haben zusammen nicht ganz 2 MB Größe, Wir Nutzen desshalb cat , um die Dateien aneinander zu hängen, und da die Gesammtgröße aller Dateien nicht ausreichen würde, haben wir sie einfach durch "bild*.jpg bild*.jpg bild*.jpg bild*.jpg" mehrere Male angegeben, (4 Mal sollte dann hier dicke reichen). (wenn man hier bei anderer Gelegenheit einmal zu viele Dateien dazu verwenden müsste, könnte eventuell die Bash einen Fehler bringen, zu viele Argumente, dann kann man schrittweise vorgehen)
Den so erzeugten Datenstrom von cat leiten wir per Pipe an dd weiter und mit "bs=1024K count=5" erzeugen wir dann ein genau 5MB großes File daraus, die typische Eigenschaften eines solchen JPEG Bilddatei hat, obwohl sie selbst kein (ein fehlerbehaftes) Bild ist.