我还没有用过dd,但是到目前为止,这还没有使我失望。现在,我已经将dd进行了12个小时以上的工作-我正在将映像写回到它来自的磁盘中-我有点担心,因为我能够从磁盘将dd映像在大约7个小时内。

我在配备Core 2 Duo的MacBook上运行OSX 10.6.6,速度为2.1ghz / core,带有4GB RAM。我正在从7200rpm硬盘驱动器(引导驱动器)上的.dmg中读取,并且正在写入通过SATA-USB连接器连接的7200rpm驱动器。我在默认情况下保留了块大小,图像约为160gb。不过,下一次,我将通过dd运行它,并使用pv对其进行跟踪。感谢大家的帮助。

评论

没有回答您的问题,但是IMO的时间很高。您是否还记得将默认的512字节以外的更大的块大小传递给dd?考虑到您的RAM,磁盘大小和速度,dd ... bs = 16M是我的建议。

我没有,只是因为我想安全玩。不过,下次我会尝试的。谢谢。

根据我的经验,Mac OS X上的dd趋于冻结,以至于我什至无法终止进程,而不得不重新启动系统。然后,我求助于在Linux VM上进行工作。

#1 楼

您可以使用dd命令向kill发送特定信号,以使其输出当前状态。该信号在BSD系统(包括OSX)上是INFO,在Linux上是USR1。在您的情况下:

kill -INFO $PID


您可以使用$PID命令找到进程ID(上面的ps);或在Mac os x上查看pgrep和pkill替代方法,以获得更方便的方法。

以Linux为例,可以使所有活动的ctrl-T进程的输出状态如下:

pkill -USR1 -x dd


输出状态后,INFO将继续应对。

评论


哦,太酷了。您可以将它们与pkill -USR1 -x dd结合使用

– Michael Mrozek
2011年4月13日在17:26

@kivetros:在BSD系统上,您需要发送INFO信号。 Linux没有SIGINFO,而是使用USR1。

–吉尔斯'所以-不再是邪恶的'
2011年4月13日在18:50

SIGUSRx信号用于程序执行其所需的操作,而不是具有标准化含义。例如,当终端更改其大小并且程序可能需要重绘其屏幕时,会引发SIGWINCH。操作系统不会发送SIGUSRx,因此可以用于自定义用途。

– LawrenceC
2011年4月14日在1:17

实际上,在启动USR1信号后过早发送dd(即在bash脚本中,即启动它后的行)发送dd实际上会终止它。在两者之间放置0.1秒的睡眠,它将正确输出其进度。顺便说一句,用于测试USR1 / INFO的一个非常好的dd命令是dd if = / dev / zero of = / dev / null。 :)

–Lauritz V. Thaulow
2011年4月14日在8:51



顺便说一句,如果状态字符(默认为Ctrl + T)发送到终端,则所有“真” BSD都会将SIGINFO发送到前台进程组。但是我不知道MacOSX是否适用。

– Netch
2012年11月1日在20:14

#2 楼

在OS X(不在Linux上尝试)下,您只需在运行dd的终端中键入Ctrl + T即可。它将输出与kill -INFO $PID相同的输出,外加CPU使用率:但是将⌘+ T与Ctrl + T混合使用。

评论


哦,好了,那么CPU使用率是负担吗?

– pje
2014年9月6日20:21在

这真是一个更好的解决方案!

– Stephn_R
15年3月18日在5:41

我在Linux上的dd中尝试过,它只是将^ T回显到终端。

–mwfearnley
17年1月6日在14:48

确保在Mac终端中执行ctrl + shift + T

– JBaczuk
17年8月30日在15:31

#3 楼

对于dd,您可以发送信号。对于正在读取或写入文件的其他命令,可以使用lsof观察它们在文件中的位置。 pv

评论


PV看起来很棒-下次我一定会用它。非常感谢。

–eckza
2011年4月14日在1:27

+1-PV看起来就像门票。

– boehj
2011年7月13日在7:00

#4 楼

一种更通用的方法是使用iotop来显示每个程序的当前磁盘读取/写入量。对此评论)。

评论


这也是我首选的快速检查方法。 iotop -o将隐藏未执行IO的进程,并使其一目了然。

–杰森C
2014年6月4日19:51

#5 楼

我通常将strace附加到这样一个正在运行的进程(带有-p $PID选项),以查看它是否在系统调用中保持阻塞或是否仍处于活动状态。

或者,如果您对向运行中的dd发送信号感到不安,请启动另一个dd以验证其是否有效。

评论


您将如何精确地附加strace?另外,我确实启动了另一个dd并向其中发送了建议的信号之一,并且...杀死了它。

–eckza
2011年4月14日在13:15

如果您知道正在运行的dd进程的pid,只需执行strace -p 。您应该看到该进程调用的所有系统调用的日志(主要是读写)

– philfr
2011年4月14日14:07



#6 楼

对于下一次,您可以从一开始就使用pv(如果可以通过软件包管理器使用它,请安装它)。这是一个实用程序,其唯一目的是通过管道传输输入来输出并监视进度和速度。

然后将映像写入驱动器,例如以4MB块大小:

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


除了初始缓冲(如果需要,可以通过dd进行最终同步补偿),这将显示进度条,平均速度,当前速度和ETA。 br />
iflag=fullblock选项强制dd通过pv捕获完整的输入块,否则您将无法决定块大小。
要使用另一种方法,请使用dd读取和pv写入,但是如果源是块设备,则必须显式指定大小。对于4GB设备:

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


还可以自动确定大小,例如:

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


依次执行ddpv的顺序实际上并不重要,这完全与性能相关-如果要读取或读取的设备对于某些块大小具有最佳性能,则您想使用dd而不是pv来访问该设备。如果需要,您甚至可以在两端都贴上dd,或者根本不在意的话根本不用:

#7 楼

coreutils v8.24开始,dd具有显示进度的本机支持。只需添加选项status=progress即可。

示例:

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




评论


linux的最佳答案。我尝试使用ubuntu并成功。在Mac中Ctrl + T

–byOnti
20/09/10在19:18

#8 楼

ddrescue会在运行时为您提供统计信息。

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

评论


这可能对下次有用,但不会帮助OP了解当前命令是否冻结。

–user22304
2012年11月2日13:11

#9 楼

有时您可能无法使用INFO或USR1信号,因为无法访问dd进程的stderr流(例如,因为执行它的终端已经关闭)。在这种情况下,一种解决方法是执行以下操作(在FreeBSD上进行测试,在Linux上可能会略有不同):



使用iostat估算平均写入率(MB / s)到目标设备,例如:

iostat -d -w30 ada0

在此处用目标设备名称替换ada0,然后等待一分钟,以得出一些结果。 “ w”参数确定样本之间的间隔秒数。增大它可以得到更好的平均估计,并且方差较小,但是您必须等待更长的时间。


使用ps确定dd的运行时间:

ps -xo etime,command | grep dd

将其转换为秒以获取运行时的总秒数。

将运行时的总秒数乘以平均写入率即可获得传输的总MB。

通过以下方法获取设备大小(以MB为单位):

grep ada0 /var/run/dmesg.boot
用目标设备名称替换ada0。将结果除以平均写入率即可得到总传输时间(以秒为单位)。减去到目前为止已运行的时间以节省时间。


仅当dd自开始以来一直以当前的平均写入速率连续写入时,此策略才有效。如果其他进程正在争用CPU或I / O资源(包括I / O总线),则可能会降低传输速率。

#10 楼

我开始使用dcfldd(1),它以更好的方式显示了dd操作。

#11 楼

您可以使用progress,它特别显示正在运行的dd的进度。它使用/proc/$pid/fd/proc/$pid/fdinfo,您也可以手动对其进行监视。

#12 楼

在执行dd时,我以root用户身份在另一个终端中运行此命令:命令完成后退出。

评论


非常酷。在El Capitan领导下工作得很好

– Stefano Mtangoo
17 Mar 9 '17 at 13:51

#13 楼

wchar中的/proc/$pid/io行(手写字符)可以为您提供有关dd进程的准确信息。只要它更改,您的dd仍然可以正常工作!与php filename.php相比,观看dd的好处是不必在端子之间进行切换,这并不总是一种选择。

<?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";
}


#14 楼

如果写入慢速驱动器(例如USB驱动器),则可能不仅要了解命令dd本身的进度,还要了解实际写入目标设备的进度。

<知道进程何时完成的一种方法是在dd命令后运行sync并等待它完成刷新缓冲区的过程,以便终端窗口返回提示。但是仍然没有进展。您可以通过例如使用mkusb的shellscript watch-flush观察“脏”数据来监视刷新的进度。此shell脚本使用系统文件/proc/meminfo中的数据。更简单地修改dd命令行以使其定期刷新缓冲区,例如在写入每个兆字节后,同时显示进度,例如
sudo dd if=file.img bs=1M of=/dev/sdx status=progress oflag=dsync

请检查并仔细检查,以指定正确的目标设备。否则,您可能会覆盖有价值的数据。 dd完全按照您的指示进行操作,因此,它已赢得了“数据销毁者”的绰号。克隆任务。它会在dd周围缠上一条安全带:可以帮助您识别目标设备,并在启动该过程之前对其进行仔细检查。