Woher weiß ich, ob dd noch funktioniert?

147

Ich habe nicht ddso viel benutzt, aber bisher ist es mir noch nicht durchgefallen. Im Moment habe ddich mehr als 12 Stunden Zeit - ich schreibe ein Image zurück auf die Festplatte, von der es stammt - und ich mache mir ein wenig Sorgen, da ich in der Lage war, ddin etwa von der Festplatte auf das Image zu wechseln 7 Stunden.

Ich verwende OSX 10.6.6 auf einem MacBook mit einem Core 2 Duo mit 2,1 GHz / Core und 4 GB RAM. Ich lese von einer .dmg-Datei auf einer Festplatte mit 7200 U / min (dem Startlaufwerk) und schreibe auf ein Laufwerk mit 7200 U / min, das über einen SATA-zu-USB-Anschluss angeschlossen ist. Ich habe die Blockgröße standardmäßig belassen und das Bild ist ungefähr 160 GB groß.

EDIT: Und nach 14 Stunden reinen Stresses hat das doch ddeinwandfrei geklappt. Das nächste Mal werde ich es jedoch durchgehen pvund nachverfolgen strace. Vielen Dank an alle für Ihre Hilfe.

eckza
quelle
7
Beantworten Sie Ihre Frage nicht, aber Ihre Zeiten sind IMO ziemlich hoch. Haben Sie daran gedacht, eine größere Blockgröße als die Standardgröße von 512 Byte an dd zu übergeben? dd ... bs=16Mist mein Vorschlag, angesichts Ihres Arbeitsspeichers, Ihrer Festplattengröße und Geschwindigkeit.
Juliano
Ich habe es nicht getan, nur weil ich auf Nummer sicher gehen wollte. Das werde ich aber nächstes Mal versuchen. Vielen Dank.
Eckza
Meiner Erfahrung ddnach friert Mac OS X so oft ein, dass ich den Prozess nicht mehr beenden kann, sondern das System neu starten muss. Ich greife dann auf die Arbeit an einer Linux-VM zurück.
SSC

Antworten:

173

ddMit dem killBefehl können Sie ein bestimmtes Signal senden , damit es seinen aktuellen Status ausgibt. Das Signal ist INFOauf BSD-Systemen (einschließlich OSX) und USR1unter Linux. In deinem Fall:

kill -INFO $PID

Sie finden die Prozess-ID ( $PIDoben) mit dem psBefehl; Oder lesen Sie pgrep- und pkill-Alternativen unter Mac OS X, um bequemere Methoden zu finden.

Einfacher gesagt, wie AntoineG in seiner Antwort hervorhebt , können Sie ctrl-Tin der Shell, in der dd ausgeführt wird, das INFOSignal eingeben .

Als Beispiel für Linux könnten Sie alle aktiven ddProzesse so ausgeben lassen:

pkill -USR1 -x dd

Nach der Ausgabe des Status ddwird der Kopiervorgang fortgesetzt.

Caleb
quelle
9
Oh, sehr cool. Sie können diese mitpkill -USR1 -x dd
Michael Mrozek
9
@kivetros: Auf BSD-Systemen müssen Sie das INFOSignal senden . Linux hat kein SIGINFO und verwendet USR1stattdessen.
Gilles
5
Mit den SIGUSRx-Signalen können Programme tun, was sie wollen, anstatt eine standardisierte Bedeutung zu haben. SIGWINCH wird beispielsweise ausgelöst, wenn das Terminal seine Größe geändert hat und das Programm möglicherweise seinen Bildschirm neu zeichnen muss. Das Betriebssystem sendet keine SIGUSRx-Dateien, sodass sie für benutzerdefinierte Zwecke zur Verfügung stehen.
LawrenceC
11
Wenn Sie dd das USR1-Signal zu früh nach dem Start senden (dh in einem Bash-Skript die Zeile nach dem Start), wird es tatsächlich beendet. Legen Sie eine Pause von 0,1 Sekunden dazwischen, und der Fortschritt wird korrekt ausgegeben. Übrigens ist ein sehr netter dd-Befehl zum Testen von USR1 / INFO dd if=/dev/zero of=/dev/null. :)
Lauritz V. Thaulow
11
Übrigens, alle "echten" BSDs senden SIGINFO an die Vordergrundprozessgruppe, wenn das Statuszeichen (standardmäßig Strg + T) an das Terminal gesendet wird. Aber ich weiß nicht, ob das für MacOSX zutrifft.
Netch
100

Unter OS X (nicht unter Linux ausprobiert) können Sie einfach Ctrl+ Tin das laufende Terminal eingeben dd. Es wird die gleiche Ausgabe wie gedruckt kill -INFO $PID, zuzüglich der CPU-Auslastung:

load: 1.40  cmd: dd 34536 uninterruptible 3.49u 64.58s
5020305+0 records in
5020304+0 records out
2570395648 bytes transferred in 4284.349974 secs (599950 bytes/sec)

Ich habe herausgefunden, dass ich diesen Thread gelesen und versucht habe, einen neuen Tab in meinem Terminal zu öffnen, aber + Tmit Ctrl+ gemischt habe T.

AntoineG
quelle
1
Oh, OK, also loadist die CPU-Auslastung?
6.
das war so viel eine bessere lösung!
Stephn_R
Ich habe es in dd unter Linux versucht, es hallt nur ^Tzum Terminal.
Mwfearnley
1
Stellen Sie sicher, dass Sie Strg + Umschalt + T im Mac-Terminal
ausführen
26

Für ddkönnen Sie ein Signal senden . Bei anderen Befehlen, die in eine Datei lesen oder schreiben, können Sie deren Position in der Datei mit beobachten lsof.

lsof -o -p1234    # where 1234 is the process ID of the command
lsof -o /path/to/file

Wenn Sie im Voraus planen, leiten Sie die Daten weiter pv.

Gilles
quelle
1
pv sieht toll aus - das werde ich auf jeden fall beim nächsten mal nutzen. Ich danke dir sehr.
Eckza
1
+1 - pvsieht aus wie nur das Ticket.
Boehj
17

Eine allgemeinere Methode ist iotopdie Anzeige des aktuellen Lese- / Schreibvolumens pro Programm.

BEARBEITEN: iotop -oNur Programme anzeigen, die derzeit E / A-Vorgänge ausführen (danke Jason C für diesen Kommentar).

Jofel
quelle
1
Dies ist auch meine bevorzugte Schnellprüfungsmethode. iotop -overbirgt Prozesse, die keine E / A-Vorgänge ausführen, und macht es einfacher, auf einen Blick zu erkennen, was los ist.
Jason C
13

Normalerweise hänge ich an straceeinen solchen laufenden Prozess an (mit der -p $PIDOption), um zu sehen, ob er bei einem Systemaufruf blockiert bleibt oder noch aktiv ist.

Wenn Sie nervös sind, ein Signal an das laufende dd zu senden, starten Sie ein anderes dd, um zu überprüfen, ob dies funktioniert.

philfr
quelle
2
Wie genau würden Sie anhängen strace? Außerdem habe ich ein anderes gestartet ddund eines der vorgeschlagenen Signale an es gesendet, und ... es hat es getötet.
Eckza
2
Wenn Sie die PID des laufenden dd-Prozesses kennen, führen Sie einfach den Befehl strace -p <pid> aus. Sie sollten das Protokoll aller vom Prozess aufgerufenen Systemaufrufe sehen (meistens Lesen und Schreiben)
philfr
11

Für das nächste Mal können Sie es einfach pvvon Anfang an verwenden (falls es über Ihren Paketmanager verfügbar ist, installieren Sie es). Dies ist ein Dienstprogramm mit dem einzigen Zweck, die Eingabe an die Ausgabe weiterzuleiten und den Fortschritt und die Geschwindigkeit zu überwachen.

Um ein Image auf ein Laufwerk zu schreiben, sagen wir 4 MB Blockgröße:

pv -ptearb /path/to/image.bin | dd iflag=fullblock of=/dev/whatever bs=4M

Abgesehen von der anfänglichen Pufferung (die durch eine abschließende Synchronisierung ausgeglichen wird, die durchgeführt werden kann, ddwenn Sie dies möchten), werden Ihnen ein Fortschrittsbalken, die Durchschnittsgeschwindigkeit, die aktuelle Geschwindigkeit und die ETA angezeigt.

Die iflag=fullblockOption zwingt dd, volle Eingabeblöcke durchzuziehen pv, sonst sind Sie der Pipe für Blockgrößen ausgeliefert.

Verwenden Sie zum Lesen dd und zum Schreiben pv, obwohl Sie die Größe explizit angeben müssen, wenn es sich bei der Quelle um ein Blockgerät handelt. Für ein 4 GB Gerät:

dd if=/dev/whatever bs=4M | pv -ptearb -s 4096m > /path/to/image.bin

Sie können die Größe auch automatisch bestimmen, so etwas wie:

dd if=/dev/whatever bs=4M | pv -ptearb -s `blockdev --getsize64 /dev/whatever` > /path/to/image.bin

Es spielt wirklich keine Rolle, in welcher Reihenfolge Sie vorgehen ddund pvin welcher Reihenfolge Sie vorgehen. Es ist vollkommen leistungsabhängig - wenn das Gerät, auf das Sie lesen oder von dem Sie lesen, für bestimmte Blockgrößen die optimale Leistung aufweist, ddanstatt pvauf dieses Gerät zuzugreifen. Sie können sogar ddan beiden Enden ein kleben, wenn Sie möchten, oder überhaupt nicht, wenn es Ihnen egal ist:

pv -ptearb /path/to/image.bin > /dev/whatever
sync
Jason C
quelle
10

Ab coreutilsv8.24, ddhat native Unterstützung für Fortschritte zeigt. Fügen Sie einfach die Option hinzu status=progress.

Beispiel:

dd if=arch.iso of=/dev/sdb bs=4M status=progress

Quelle

Chirag Bhatia - chirag64
quelle
5

ddrescue gibt dir Statistiken, wie es läuft.

Demo: http://www.youtube.com/watch?v=vqq9A01geeA#t=144s

Ben Preston
quelle
3
Dies kann beim nächsten Mal hilfreich sein, hilft dem OP jedoch nicht zu verstehen, ob der aktuelle Befehl eingefroren ist oder nicht.
Francesco Turco
4

Manchmal können Sie das INFO- oder USR1-Signal möglicherweise nicht verwenden, weil auf den stderr-Stream des ddProzesses nicht zugegriffen werden kann (z. B. weil das Terminal, in dem es ausgeführt wurde, bereits geschlossen wurde). In diesem Fall können Sie das folgende Problem umgehen (unter FreeBSD getestet, unter Linux möglicherweise geringfügig anders):

  1. Verwenden Sie iostatdiese Option , um die durchschnittliche Schreibrate (MB / s) auf dem Zielgerät zu schätzen. Beispiel:

    iostat -d -w30 ada0

    Ersetzen Sie ada0hier den Namen Ihres Zielgeräts und warten Sie eine Minute, bis einige Ergebnisse vorliegen. Der Parameter "w" bestimmt, wie viele Sekunden zwischen den Abtastungen liegen. Wenn Sie den Wert erhöhen, erhalten Sie eine bessere Durchschnittsschätzung mit weniger Varianz. Sie müssen jedoch länger warten.

  2. Verwenden Sie psdiese Option , um zu bestimmen, wie lange ddausgeführt wurde:

    ps -xo etime,command | grep dd

    Konvertieren Sie dies in Sekunden, um die Gesamtlaufzeit in Sekunden zu erhalten.

  3. Multiplizieren Sie die gesamte Laufzeit mit der durchschnittlichen Schreibrate, um die gesamte übertragene MB zu erhalten.
  4. Holen Sie sich die Gerätegröße in MB mit:

    grep ada0 /var/run/dmesg.boot

    Ersetzen Sie den Namen Ihres Zielgeräts durch ada0. Teilen Sie das Ergebnis durch die durchschnittliche Schreibrate, um die Gesamtübertragungszeit in Sekunden zu erhalten. Subtrahieren Sie die bisher gelaufene Zeit, um die verbleibende Zeit zu erhalten.

Diese Strategie funktioniert nur, wenn ddseit Beginn kontinuierlich mit der aktuellen durchschnittlichen Schreibrate geschrieben wurde. Wenn andere Prozesse um die CPU- oder E / A-Ressourcen (einschließlich des E / A-Busses) konkurrieren, kann dies die Übertragungsrate verringern.

D Coetzee
quelle
4

Ich habe angefangen, dcfldd (1) zu verwenden, um dd-Operationen besser darzustellen.

Kartik M
quelle
2

Während der ddAusführung starte ich dies in einem anderen Terminal als root:

while pgrep ^dd; do pkill -INFO dd; sleep 1; done

Er gibt den ddStatus alle 1 Sekunde im ursprünglichen Terminalfenster aus, in dem er ddausgeführt wird, und wird beendet, wenn der Befehl ausgeführt wird.

ccpizza
quelle
So cool.
Hat
2

Sie können verwenden progress, um insbesondere den Fortschritt eines Laufs anzuzeigen dd. Es nutzt /proc/$pid/fdund /proc/$pid/fdinfo was Sie auch von Hand überwachen können.

Jofel
quelle
1

Die wcharZeile (geschriebene Zeichen) in /proc/$pid/iokann Ihnen genaue Informationen über den ddVorgang geben. Solange es sich ändert, arbeitet Ihr ddnoch!

Hier ist ein netter kleiner PHP - Skript, die Sie speichern und führen Sie dann mit php filename.phpwährend der dddas geschriebenen Bytes angezeigt werden soll . Der nette Vorteil beobachten /proc/$pid/ioüber kill -USR1 $(pidof dd)ist , dass Sie nicht zwischen den Terminals wechseln müssen, was nicht immer eine Option.

<?php

/** Time between refreshs in seconds */
$refresh = 1;


/**
 * Start of Script 
 */

if (!($pid = exec('pidof dd')))
    exit("no dd running\n");

$history = array();
$break_ms = $refresh * 1000000;
$start_time = exec("ls -ld /proc/$pid --time-style=+\"%s\" | egrep -o [0-9]{10}");


fprintf(STDOUT, "PID: %s\n", $pid);
fprintf(STDOUT, "START TIME: %s\n\n", date("Y-m-d H:i:s", $start_time));


while (true) {
    if (isset($curr))
        array_push($history, $curr);

    if (count($history) > 10) array_shift($history);
    $oldest = reset($history);
    $latest = end($history);

    /**
     * get number of written bytes from /proc/$pid/io
     */
    #if (!($curr = exec("cat /proc/$pid/io | grep ^write_bytes | sed 's/write_bytes: //g'")))
    #    break;

    /* prepare proc_open() parameter */
    $descriptorspec = array(
        0 => array('pipe', 'r'), // stdin
        1 => array('pipe', 'w'), // stdout
        2 => array('pipe', 'w'), // stderr
    );

    $process = proc_open("cat /proc/$pid/io | grep ^write_bytes | sed 's/write_bytes: //g'", $descriptorspec, $pipes);
    if (!is_resource($process)) break;

    $stdout = stream_get_contents($pipes[1]);
    $stderr = stream_get_contents($pipes[2]);
    proc_close($process);

    if (!empty($stderr)) break;
    $curr = trim($stdout);

    /**
     * caculate elapsed time from start */
    $time_elapsed = time() - $start_time;

    /**
     * avg speed since start */
    $avg = $time_elapsed > 0 ? round($curr / $time_elapsed) : 0;

    /**
     * avg speed of last 10 updates */
    if (count($history) > 0)
        $speed = human_file_size(round(($latest - $oldest) / count($history) / $refresh));

    $output = sprintf("\rBYTES WRITTEN: %s [%s]  ::  CURRENT: %s/s  ::  AVERAGE: %s/s  ::  ELAPSED: %s", $curr, human_file_size($curr), isset($speed) ? $speed : 0, human_file_size($avg), gmdate("H:i:s", $time_elapsed));
    printf("%s%s", $output, str_repeat(" ", exec("tput cols") - strlen($output)));

    usleep($break_ms);
}

fprintf(STDOUT, "\ndd has finished!\n\n");

function human_file_size($size,$unit="") {
  if( (!$unit && $size >= 1<<30) || $unit == "GB")
    return number_format($size/(1<<30),2)." GB";
  if( (!$unit && $size >= 1<<20) || $unit == "MB")
    return number_format($size/(1<<20),2)." MB";
  if( (!$unit && $size >= 1<<10) || $unit == "kB")
    return number_format($size/(1<<10),2)." kB";
  return number_format($size)." bytes";
}
Leon Kramer
quelle