dd vs cat - dd vẫn còn liên quan những ngày này?


122

Gần đây tôi nhận ra rằng chúng ta có thể sử dụng catnhiều như vậy dd, và nó thực sự nhanh hơndd

Tôi biết rằng nó ddrất hữu ích trong việc xử lý các băng trong đó kích thước khối thực sự quan trọng về tính chính xác, không chỉ hiệu suất. Tuy nhiên, trong những ngày này, có những tình huống ddcó thể làm điều gì đó catkhông thể? (Ở đây tôi cho rằng sự khác biệt hiệu suất dưới 20% không liên quan.)

Ví dụ cụ thể sẽ tốt đẹp!


1
Xem câu hỏi SO này cho một ví dụ cụ thể.
camh

Câu trả lời:


156

Về hình thức, ddlà một công cụ từ hệ điều hành IBM vẫn giữ được hình dáng bên ngoài (thông số truyền qua), thực hiện một số chức năng rất hiếm khi được sử dụng (như chuyển đổi EBCDIC sang ASCII hoặc đảo ngược endianness không phải là nhu cầu phổ biến hiện nay).

Tôi đã từng nghĩ rằng ddviệc sao chép các khối dữ liệu lớn trên cùng một đĩa nhanh hơn (do sử dụng bộ đệm hiệu quả hơn), nhưng điều này không đúng , ít nhất là trên các hệ thống Linux ngày nay.

Tôi nghĩ rằng một số ddtùy chọn hữu ích khi xử lý băng, trong đó việc đọc thực sự được thực hiện theo khối (trình điều khiển băng không ẩn các khối trên phương tiện lưu trữ theo cách mà trình điều khiển đĩa thực hiện). Nhưng tôi không biết chi tiết cụ thể.

Một điều ddcó thể làm mà không thể (dễ dàng) được thực hiện bởi bất kỳ công cụ POSIX nào khác là lấy N byte đầu tiên của luồng. Nhiều hệ thống có thể làm điều đó với head -c 42, nhưng head -c, trong khi phổ biến, không có trong POSIX (và không có sẵn ngày hôm nay trên ví dụ OpenBSD). ( tail -clà POSIX.) Ngoài ra, ngay cả khi head -ccó tồn tại, nó có thể đọc quá nhiều byte từ nguồn (vì nó sử dụng bộ đệm stdio bên trong), đây là một vấn đề nếu bạn đọc từ một tệp đặc biệt khi chỉ đọc có hiệu lực. (Coreutils GNU hiện tại đọc số đếm chính xác với head -c, nhưng FreeBSD và NetBSD sử dụng stdio.)

Tổng quát hơn, ddcung cấp giao diện cho API tệp cơ bản duy nhất trong số các công cụ Unix: chỉ ddcó thể ghi đè hoặc cắt bớt tệp tại bất kỳ điểm nào hoặc tìm kiếm trong tệp. (Đây là ddkhả năng độc đáo của nó, và nó là một khả năng lớn; đủ kỳ lạ ddđược biết đến với những điều mà các công cụ khác có thể làm.)

  • Hầu hết các công cụ Unix ghi đè lên tệp đầu ra của chúng, tức là xóa nội dung của nó và bắt đầu lại từ đầu. Đây là những gì xảy ra khi bạn sử dụng >chuyển hướng trong vỏ là tốt.
  • Bạn có thể nối vào nội dung của tệp với >>chuyển hướng trong trình bao hoặc với tee -a.
  • Nếu bạn muốn rút ngắn một tệp bằng cách xóa tất cả dữ liệu sau một điểm nhất định , điều này được hỗ trợ bởi kernel C và API C bên dưới thông qua truncatechức năng, nhưng không bị lộ bởi bất kỳ công cụ dòng lệnh nào ngoại trừdd :

    dd if=/dev/null of=/file/to/truncate seek=1 bs=123456  # truncate file to 123456 bytes
    
  • Nếu bạn muốn ghi đè dữ liệu vào giữa tệp, một lần nữa, điều này có thể xảy ra trong API phục hồi bằng cách mở tệp để ghi mà không cắt bớt (và gọi lseekđể di chuyển đến vị trí mong muốn nếu cần), nhưng chỉ ddcó thể mở tệp mà không cần cắt ngắn hoặc nối thêm, hoặc tìm kiếm từ vỏ ( ví dụ phức tạp hơn ).

    # zero out the second kB block in the file (i.e. bytes 1024 to 2047)
    dd if=/dev/zero of=/path/to/file bs=1024 seek=1 count=1 conv=notrunc
    

Vì vậy, Là một công cụ hệ thống, ddkhá vô dụng. Là một công cụ xử lý văn bản (hoặc tệp nhị phân), nó khá có giá trị!


Được chấp nhận bởi vì tôi nghĩ rằng nó giải thích ý chính của các câu trả lời khác ( truncseekcó thể sử dụng được dd).
kizzx2

2
Một cách sử dụng đặc biệt hơn: ddcó thể đọc dữ liệu nhị phân từ các bộ mô tả tệp không thể xóa được mà không có khả năng phá hủy dữ liệu chưa đọc do bộ đệm stdio. Xem ở đây để biết ví dụ: etalabs.net/sh_tricks.html
R ..

2
@R ..: Vâng. Trong GNU coreutils 6.10, head -c Ncác cuộc gọi readvà không bao giờ vượt quá N. Trong NetBSD 5.1, head -ccác cuộc gọi getc. Trong FreeBSD 7.4, head -ccác cuộc gọi fread.
Gilles

1
Coreutils ddcũng đưa O_DIRECT (v.v.) vào kịch bản shell, mà tôi nghĩ cũng là duy nhất.
derobert

1
Coreutils truncatecho phép cắt ngắn hoặc mở rộng các tệp, do đó loại bỏ việc sử dụng khác dd.
dcoles 17/11/18

22

Các ddlệnh bao gồm nhiều lựa chọn mà mèo không có khả năng thích ứng. Có lẽ trong trường hợp sử dụng của bạn, mèo là một sự thay thế hoàn toàn khả thi, nhưng nó không phải là một sự thay thế dd.

Một ví dụ sẽ được sử dụng ddđể sao chép một phần của một cái gì đó nhưng không phải là toàn bộ. Có lẽ bạn muốn tách ra một số bit từ giữa hình ảnh iso hoặc bảng phân vùng từ ổ đĩa cứng dựa trên một vị trí đã biết trên thiết bị. Với ddbạn có thể chỉ định các tùy chọn bắt đầu, dừng và số lượng cho phép các hành động này.

Các tùy chọn này ddlàm cho nó không thể thiếu đối với thao tác dữ liệu hạt mịn trong khi cat* chỉ có thể hoạt động trên toàn bộ đối tượng tệp, thiết bị hoặc luồng.

* Theo ghi nhận của Gilles trong các bình luận, có thể kết hợp catvới các công cụ khác để cô lập các bộ phận của một cái gì đó, nhưng catvẫn hoạt động trên toàn bộ đối tượng.


5
ddthực sự không có gì để làm với các thiết bị cấp thấp, nó cần một mục /devgiống như các thiết bị khác. Bạn có thể sao chép toàn bộ phân vùng với cathoặc một phần của nó tail +c $(($start+1)) | head -c $count.
Gilles

16
Tất nhiên. ;-) Và khi tôi đưa hình ảnh đĩa 1.6TB vào cat | head | tailđể lấy vài MB cuối cùng, đĩa quay lên sẽ hút mặt trăng đến gần trái đất hơn.
Caleb

2
@Gilles Xin lỗi tôi có nghĩa là phải thừa nhận rằng việc tôi sử dụng thuật ngữ "mức độ thấp" không phải là từ điển tốt, mặc dù tôi đã đề cập đến dữ liệu trên thiết bị, không phải thiết bị. Có lẽ "thao tác dữ liệu tinh chỉnh" sẽ tốt hơn "thao tác dữ liệu cấp thấp".
Caleb

21

Không ai đã đề cập rằng bạn có thể sử dụng dd để tạo các tệp thưa thớt , mặc dù truncatecũng có thể được sử dụng cho cùng một mục đích.

dd if=/dev/zero of=sparse-file bs=1 count=1 seek=10GB

Điều này gần như ngay lập tức và tạo ra một tệp lớn tùy ý có thể được sử dụng làm tệp loopback chẳng hạn:

loop=`losetup --show -f sparse-file`
mkfs.ext4 $loop
mkdir myloop
mount $loop myloop

Điều thú vị là ban đầu nó chỉ sử dụng một khối không gian đĩa duy nhất và sau đó chỉ phát triển khi cần thiết (định dạng ext4 của tệp 10 GB tiêu tốn 291 MB trên hệ thống của tôi). Sử dụng duđể xem dung lượng đĩa thực sự được sử dụng - lschỉ báo cáo kích thước tối đa mà tệp có thể tăng lên.


4
ls -lscho bạn thấy kích thước thưa thớt.
jmtd

2
Lệnh của bạn ghi một byte vô dụng vào tệp. dd of=sparse-file bs=1 count=0 seek=10Gsẽ tương đương với truncate -s 10GB sparse-file. Đủ khó hiểu truncateddcó cách giải thích ngược lại chính xác GBso với G...
frostschutz

5
@frostschutz: man ddnói: MB =1000*1000, M =1024*1024vân vân. Và man truncatenói:, MB 1000*1000, M 1024*1024vì vậy không có sự khác biệt. Tôi sử dụng cả hai ddtruncatetừ lõi GNU. Bạn cũng nên làm như vậy! :-)
erik

@erik: Cảm ơn đã sửa. Nếu nó không được thay đổi gần đây, tôi phải nhầm lẫn nó với một cái gì đó khác.
frostschutz

10

Ghi đè các phân đoạn cụ thể của ổ cứng bằng một cái gì đó là một ví dụ phổ biến. Ví dụ: bạn có thể muốn xóa MBR của mình bằng lệnh này:

dd if=/dev/zero of=/dev/sda bs=446 count=1

Ngoài ra, bạn có thể tạo các tệp trống với nó (giả sử hình ảnh đĩa lặp):

dd if=/dev/zero of=10mb.file bs=1024k count=10

Bên cạnh đó, lệnh thứ hai đó là cách nhanh nhất mà tôi biết để sử dụng tối đa 10MB
Kevin M

3
@Kevin: Nhanh hơn head -c? Hãy chia sẻ một điểm chuẩn !
Gilles

9

ddrất hữu ích để sao lưu khu vực khởi động của ổ cứng hoặc thiết bị lưu trữ khác ( dd if=/dev/sda of=boot_sector.bin bs=512 count=1) và sau đó viết lại nó ( dd if=boot_sector.bin of=/dev/sda). Nó cũng hữu ích tương tự để sao lưu các tiêu đề của khối lượng mã hóa.

catcó thể có thể bị vặn vẹo khi làm điều đó nhưng tôi sẽ không tin vào phần viết lại. Thật khó để catchỉ đọc / ghi một số byte nhất định.


5

Gần đây tôi đã có lần đầu tiên nhân bản một số phân vùng nhiều GB 100 GB trong lịch sử linuxing của mình (cf cp -arhoặc rsyncđã phục vụ tốt cho tôi nhiều lần). Tất nhiên tôi đã chuyển sang dd'vì mọi người đều biết đó là những gì bạn sử dụng ... và đã bị hiệu suất kinh hoàng. Một chút googling sớm dẫn tôi đến ddrescue, điều mà tôi đã sử dụng một vài lần bây giờ và hoạt động rất tốt (nhanh hơn nhiều so với dd).


1
ddrescuelà tuyệt vời, đặc biệt là để lấy dữ liệu ra khỏi các đĩa bị lỗi.
ryenus

5

Dưới đây là một số thủ thuật dd tôi đã nghĩ ra trong nhiều năm qua ..

Cắt và dán trên bash chế độ không thân thiện hoặc không tương tác

Nếu bạn đang ở trong tình huống không phát hiện thấy EOF / ^ D / ^ F, bạn có thể sử dụng dd để truyền tệp văn bản đến máy chủ lưu trữ. Vì nó sẽ dừng đọc sau một lượng byte được chỉ định tự động.

Tôi đã sử dụng điều này gần đây như năm ngoái trong một cuộc tập trận bảo mật nơi chúng tôi có thể nhận được các shell không tty trên một máy chủ từ xa và cần phải chuyển các tập tin vào.

Trong thực tế, tôi thậm chí đã thực hiện một vài tệp nhị phân bằng cách mã hóa base64 và sử dụng tập lệnh giải mã base64 bash chậm nhưng đáng tin cậy.

dd of=textfile.txt bs=1 count=<size_of_data_in_paste_buffer>

Một mẹo cực hay là trong khi dd đang chạy, nếu bạn gửi tín hiệu USR1, nó sẽ phát ra trạng thái hiện tại (byte đọc, byte mỗi giây ..)

Bộ lọc trạng thái thông lượng phổ quát

Tôi đã viết cái này để hoạt động như một bộ lọc tiến trình bash thuần túy cho bất kỳ chương trình nào phát ra dữ liệu thông qua thiết bị xuất chuẩn. (Lưu ý: Khá nhiều thứ sẽ phát ra dữ liệu thông qua thiết bị xuất chuẩn - đối với các chương trình không có, bạn có thể gian lận nếu chúng không chặn bạn bằng cách sử dụng / dev / stdout làm tên tệp. Nhưng về cơ bản, mỗi khi bạn nhận được X số lượng byte, in dấu băm (như FTP trường học cũ khi bạn bật chế độ băm)

(Lưu ý) Điều tập tin tiến trình là khập khiễng, điều này chủ yếu là một bằng chứng về khái niệm. Nếu tôi làm lại nó, tôi sẽ sử dụng một biến.

 dd bs=$BLKSZ of=${TMPFILE} 2>&1 \
                | grep --line-buffered -E '[[:digit:]]* bytes' \
                | awk '{ print $1 }' >> ${PROGRESS} &

 while [[ $(pidof dd) -gt 1 ]]; do

        # PROTIP: You can sleep partial seconds
        sleep .5

        # Force dd to update us on it's progress (which gets
        # redirected to $PROGRESS file.    
        pkill -USR1 dd
        local BYTES_THIS_CYCLE=$(tail -1 $PROGRESS)
        local XFER_BLKS=$(((BYTES_THIS_CYCLE-BYTES_LAST_CYCLE)/BLKSZ))

        if [ $XFER_BLKS -gt 0 ]; then
                printf "#%0.s" $(seq 0 $XFER_BLKS)
                BYTES_LAST_CYCLE=$BYTES_THIS_CYCLE
        fi
done

tập tin lát và sử dụng tập tin shell ẩn danh

Đây là một ví dụ mã giả cực kỳ về cách bạn có thể có một tệp tar đã ký mà bạn có thể trích xuất mà không gặp lỗi bằng cách cung cấp đầu vào tar thông qua một tập tin ẩn danh - mà không sử dụng bất kỳ tệp tmp nào để lưu trữ dữ liệu tệp một phần.

generate_hash() {
    echo "yay!"
}

# Create a tar file, generate a hash, append it to the end
tar -cf log.tar /var/log/* 2>/dev/null
TARFILE_SIZE=$(stat -f "%z" log.tar)
SIGNATURE=$(generate_hash log.tar)
echo $SIGNATURE >>log.tar

# Then, later, extract without getting an error..

tar xvf <(dd if=$OLDPWD/log.tar bs=1 count=${TARFILE_SIZE})

Các tl; dr là: Tôi thấy dd cực kỳ hữu ích. Và đây chỉ là ba ví dụ tôi có thể nghĩ ra khỏi đỉnh đầu.


4

Bạn có thể chuyển hướng một số nội dung đầu ra. Nó đặc biệt hữu ích, nếu bạn cần viết bằng sudo:

echo some_content | sudo dd status=none of=output.txt

Bên cạnh đó, sudonó tương đương với:

echo some_content > output.txt

hoặc để này:

echo some_content | sudo tee output.txt > /dev/null

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.