Làm sao để biết dd vẫn hoạt động?


147

Tôi đã không sử dụng ddnhiều như vậy, nhưng cho đến nay nó vẫn chưa làm tôi thất vọng. Ngay bây giờ, tôi đã có ddhơn 12 giờ - tôi đang viết một hình ảnh trở lại đĩa mà nó đến từ - và tôi hơi lo lắng, vì tôi có thể chuyển ddtừ đĩa sang hình ảnh trong khoảng 7 giờ.

Tôi đang chạy OSX 10.6.6 trên MacBook với Core 2 Duo với tốc độ 2.1ghz / lõi với RAM 4gb. Tôi đang đọc từ một .dmg trên ổ cứng 7200rpm (ổ đĩa khởi động) và tôi đang ghi vào ổ 7200rpm được kết nối qua đầu nối SATA-USB. Tôi để mặc định kích thước khối và hình ảnh khoảng 160gb.

EDIT: Và, sau 14 giờ căng thẳng thuần túy, ddtất cả đã hoạt động hoàn hảo. Tuy nhiên, lần tới, tôi sẽ chạy qua pvvà theo dõi nó strace. Cảm ơn tất cả mọi người vì tất cả sự giúp đỡ của bạn.


7
Không trả lời câu hỏi của bạn, nhưng thời gian của bạn là IMO khá cao. Bạn có nhớ chuyển một kích thước khối lớn hơn cho dd khác với 512 byte mặc định không? dd ... bs=16Mlà đề xuất của tôi, với RAM, kích thước và tốc độ đĩa của bạn.
Juliano

Tôi đã không, đơn giản vì tôi muốn chơi nó an toàn. Tuy nhiên, lần sau tôi sẽ thử. Cảm ơn.
eckza

Theo kinh nghiệm của tôi, ddtrên Mac OS X có xu hướng đóng băng đến mức tôi thậm chí không thể giết tiến trình mà phải khởi động lại hệ thống. Tôi dùng đến việc thực hiện trên máy ảo Linux.
ssc

Câu trả lời:


173

Bạn có thể gửi ddmột tín hiệu nhất định bằng cách sử dụng killlệnh để làm cho nó xuất trạng thái hiện tại. Tín hiệu là INFOtrên các hệ thống BSD (bao gồm cả OSX) và USR1trên Linux. Trong trường hợp của bạn:

kill -INFO $PID

Bạn có thể tìm id tiến trình ( $PIDở trên) bằng pslệnh; hoặc xem các lựa chọn thay thế pgrep và pkill trên mac os x để biết các phương pháp thuận tiện hơn.

Đơn giản hơn, như AntoineG chỉ ra trong câu trả lời của anh ta , bạn có thể gõ ctrl-Tvào shell đang chạy dd để gửi INFOtín hiệu.

Ví dụ về Linux, bạn có thể tạo tất cả ddtrạng thái đầu ra của quy trình hoạt động như sau:

pkill -USR1 -x dd

Sau khi xuất trạng thái của nó, ddsẽ tiếp tục đối phó.


9
Ồ, rất tuyệt. Bạn có thể kết hợp những người vớipkill -USR1 -x dd
Michael Mrozek

9
@kivetros: Trên các hệ thống BSD, bạn cần gửi INFOtín hiệu. Linux không có SIGINFO và sử dụng USR1thay thế.
Gilles

5
Các tín hiệu SIGUSRx dành cho các chương trình thực hiện những gì chúng muốn, trái ngược với việc có ý nghĩa chuẩn hóa. SIGWINCH, ví dụ, được nâng lên khi thiết bị đầu cuối đã thay đổi kích thước của nó và chương trình có thể cần phải vẽ lại màn hình của nó. Hệ điều hành không gửi SIGUSRx để chúng có sẵn cho sử dụng tùy chỉnh.
LawrenceC

11
Gửi dd tín hiệu USR1 quá sớm sau khi nó bắt đầu (nghĩa là trong tập lệnh bash, dòng sau khi bạn khởi động nó) thực tế sẽ chấm dứt nó. Đặt một giấc ngủ 0,1 giây ở giữa và nó sẽ tạo ra tiến trình của nó đúng cách. Nhân tiện, một lệnh dd rất hay để kiểm tra USR1 / INFO trên là dd if=/dev/zero of=/dev/null. :)
Lauritz V. Thaulow

11
BTW, tất cả các BSD "thật" đều gửi SIGINFO đến nhóm quy trình tiền cảnh nếu ký tự trạng thái (Ctrl + T theo mặc định) được gửi đến thiết bị đầu cuối. Nhưng tôi không biết liệu điều đó có đúng với MacOSX không.
Netch

100

Trong OS X (không thử trên Linux), bạn chỉ cần nhập Ctrl+ Ttrong thiết bị đầu cuối đang chạy dd. Nó sẽ in cùng một đầu ra như kill -INFO $PID, cộng với việc sử dụng CPU:

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)

Tôi phát hiện ra nó đang đọc chủ đề này và cố gắng mở một tab mới trong thiết bị đầu cuối của mình nhưng trộn + Tvới Ctrl+ T.


1
Oh, OK, vậy loadlà sử dụng CPU?
pje

đây là một giải pháp tốt hơn
Stephn_R 18/03/2015

Tôi đã thử trong dd trên Linux, nó chỉ lặp lại ^Tvới thiết bị đầu cuối.
mwfearnley

1
đảm bảo bạn đang thực hiện ctrl + shift + T trong thiết bị đầu cuối mac
JBaczuk

26

Đối với dd, bạn có thể gửi tín hiệu . Đối với các lệnh khác đang đọc hoặc ghi vào tệp, bạn có thể xem vị trí của chúng trong tệp với lsof.

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

Nếu bạn có kế hoạch trước, đường ống dữ liệu thông qua pv.


1
pv trông tuyệt vời - tôi chắc chắn sẽ sử dụng nó vào lần tới. Cảm ơn bạn rất nhiều.
eckza

1
+1 - pvtrông giống như chỉ là vé.
boehj

17

Một cách tổng quát hơn là sử dụng iotophiển thị số lượng đọc / ghi đĩa hiện tại trên mỗi chương trình.

EDIT: iotop -ochỉ hiển thị các chương trình thực hiện các hoạt động I / O hiện tại (cảm ơn Jason C về nhận xét này).


1
Đây là phương pháp kiểm tra nhanh ưa thích của tôi là tốt. iotop -osẽ ẩn các quy trình không thực hiện IO và giúp dễ dàng nói nhanh hơn những gì đang diễn ra.
Jason C

13

Tôi thường đính kèm stracevới một quy trình đang chạy như vậy (với -p $PIDtùy chọn) để xem liệu nó có bị chặn trong một cuộc gọi hệ thống hay nếu nó vẫn còn hoạt động.

Hoặc, nếu bạn cảm thấy lo lắng về việc gửi tín hiệu đến dd đang chạy, hãy bắt đầu một dd khác để xác thực nếu điều này hoạt động.


2
Làm thế nào chính xác bạn sẽ đi về đính kèm strace? Ngoài ra, tôi đã bắt đầu một cái khác ddvà gửi một trong những tín hiệu được đề xuất đến nó, và ... nó đã giết chết nó.
eckza

2
Nếu bạn biết pid của tiến trình dd đang chạy, chỉ cần thực hiện strace -p <pid>. Bạn sẽ thấy nhật ký của tất cả các cuộc gọi hệ thống được gọi theo quy trình (chủ yếu là đọc và viết)
philfr

11

Lần sau, bạn chỉ có thể sử dụng pvtừ đầu (nếu có sẵn thông qua trình quản lý gói của bạn, hãy cài đặt nó). Đây là một tiện ích với mục đích duy nhất là đầu vào đường ống đến đầu ra và theo dõi tiến độ và tốc độ.

Sau đó, để ghi hình ảnh vào ổ đĩa, hãy nói với kích thước khối 4MB:

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

Ngoài bộ đệm ban đầu (được bù bởi đồng bộ hóa cuối cùng, có thể được thực hiện thông qua ddnếu bạn muốn), điều này sẽ cho bạn thấy một thanh tiến trình, tốc độ trung bình, tốc độ hiện tại và ETA.

Các iflag=fullblocklực lượng tùy chọn dd để lấy khối đầy đủ các đầu vào thông qua pv, nếu không bạn đang ở lòng thương xót của các đường ống cho các kích cỡ khối.

Để đi theo cách khác, sử dụng dd để đọc và pv để viết, mặc dù bạn phải xác định rõ kích thước nếu nguồn là một thiết bị khối. Đối với thiết bị 4GB:

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

Bạn cũng có thể xác định kích thước tự động, đại loại như:

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

Thực sự không quan trọng bạn thực hiện theo thứ tự nào ddpvhoàn toàn liên quan đến hiệu suất - nếu thiết bị bạn đang đọc hoặc từ đó có hiệu suất tối ưu cho các khối nhất định bạn muốn sử dụng ddthay vì pvtruy cập vào thiết bị đó. Bạn thậm chí có thể dán một đầu ddở cả hai đầu nếu bạn muốn, hoặc hoàn toàn không nếu bạn không quan tâm:

pv -ptearb /path/to/image.bin > /dev/whatever
sync

10

Kể từ coreutilsv8.24, ddcó hỗ trợ riêng để hiển thị tiến trình. Chỉ cần thêm tùy chọn status=progress.

Thí dụ:

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

Nguồn



4

Đôi khi bạn không thể sử dụng tín hiệu INFO hoặc USR1 vì luồng stderr của ddquá trình không thể truy cập được (ví dụ: vì thiết bị đầu cuối trong đó nó đã được thực thi đã bị đóng). Trong trường hợp này, một cách giải quyết là thực hiện các thao tác sau (được thử nghiệm trên FreeBSD, có thể hơi khác trên Linux):

  1. Sử dụng iostatđể ước tính tốc độ ghi trung bình (MB / s) cho thiết bị đích, ví dụ:

    iostat -d -w30 ada0

    Thay thế tên thiết bị mục tiêu của bạn ada0ở đây và đợi một phút để nó đưa ra một vài kết quả. Tham số "w" xác định có bao nhiêu giây giữa các mẫu. Việc tăng nó sẽ cho ước tính trung bình tốt hơn với ít phương sai hơn, nhưng bạn sẽ phải chờ lâu hơn.

  2. Sử dụng psđể xác định thời gian ddđã chạy:

    ps -xo etime,command | grep dd

    Chuyển đổi này thành giây để có được tổng số giây thời gian chạy.

  3. Nhân tổng số giây thời gian chạy với tốc độ ghi trung bình để có tổng MB được chuyển.
  4. Lấy kích thước thiết bị tính bằng MB với:

    grep ada0 /var/run/dmesg.boot

    Thay thế tên thiết bị mục tiêu của bạn cho ada0. Chia kết quả cho tốc độ ghi trung bình để có được tổng thời gian chuyển tính bằng giây. Trừ đi thời gian nó đã chạy cho đến nay để có thời gian còn lại.

Chiến lược này chỉ hoạt động nếu ddđã được viết liên tục ở tốc độ ghi trung bình hiện tại kể từ khi nó bắt đầu. Nếu các quy trình khác đang cạnh tranh cho tài nguyên CPU hoặc I / O (bao gồm cả bus I / O) thì nó có thể làm giảm tốc độ truyền.


4

Tôi bắt đầu sử dụng dcfldd (1), cho thấy các thao tác dd theo cách tốt hơn.


2

Trong khi ddthực thi, tôi chạy cái này trong một terminal khác với quyền root:

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

Nó in ra ddtình trạng mỗi 1 giây trong cửa sổ terminal gốc nơi ddđang thực hiện, và bỏ khi lệnh được thực hiện.


Thật tuyệt. Làm việc tốt ở đây dưới thời El Capitan
Stefano Mtangoo

2

Bạn có thể sử dụng progress, đặc biệt, cho thấy tiến trình chạy dd. Nó sử dụng /proc/$pid/fd/proc/$pid/fdinfo bạn cũng có thể theo dõi bằng tay.


1

Các wchardòng (viết ký tự) trong /proc/$pid/iocó thể cung cấp cho bạn thông tin chính xác về ddquá trình. Miễn là nó thay đổi, bạn ddvẫn đang làm việc!

Đây là một tập lệnh php nhỏ gọn, bạn có thể lưu và thực hiện php filename.phptrong khi ddhiển thị các byte được viết. Lợi ích tuyệt vời của việc xem /proc/$pid/ioqua kill -USR1 $(pidof dd)là bạn không phải chuyển đổi giữa các thiết bị đầu cuối, điều này không phải lúc nào cũng là một lựa chọn.

<?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";
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.