dd vs cat - apakah hari ini masih relevan?


122

Baru-baru ini saya menyadari bahwa kita dapat menggunakan catsebanyak mungkin dd, dan sebenarnya lebih cepat daripadadd

Saya tahu dditu berguna dalam menangani kaset di mana ukuran blok sebenarnya penting dalam kebenaran, bukan hanya kinerja. Namun, pada hari-hari ini, adakah situasi di mana ddbisa melakukan sesuatu yang cattidak bisa? (Di sini saya akan menganggap perbedaan kinerja kurang dari 20% tidak relevan.)

Contoh nyata akan menyenangkan!


1
Lihat pertanyaan SO ini untuk satu contoh nyata.
camh

Jawaban:


156

Dalam penampilan, ddadalah alat dari sistem operasi IBM yang mempertahankan penampilan asingnya (passing parameternya), yang melakukan beberapa fungsi yang sangat jarang digunakan (seperti konversi EBCDIC ke ASCII atau pembalikan endianness ... bukan kebutuhan umum saat ini).

Saya dulu berpikir bahwa dditu lebih cepat untuk menyalin blok data yang besar pada disk yang sama (karena penggunaan buffering yang lebih efisien), tetapi ini tidak benar , setidaknya pada sistem Linux saat ini.

Saya pikir beberapa ddopsi berguna ketika berhadapan dengan kaset, di mana pembacaan benar-benar dilakukan dalam blok (driver tape tidak menyembunyikan blok pada media penyimpanan seperti cara disk driver lakukan). Tapi saya tidak tahu secara spesifik.

Satu hal yang dddapat dilakukan yang tidak dapat (dengan mudah) dilakukan oleh alat POSIX lainnya adalah mengambil N byte pertama dari sebuah stream. Banyak sistem dapat melakukannya dengan head -c 42, tetapi head -c, sementara umum, tidak ada dalam POSIX (dan tidak tersedia hari ini di misalnya OpenBSD). ( tail -cadalah POSIX.) Juga, bahkan jika head -cada, mungkin membaca terlalu banyak byte dari sumber (karena menggunakan stdio buffering secara internal), yang merupakan masalah jika Anda membaca dari file khusus di mana hanya membaca memiliki efek. (Coreutils GNU saat ini membaca hitungan persisnya head -c, tetapi FreeBSD dan NetBSD menggunakan stdio.)

Secara lebih umum, ddmemberikan antarmuka ke file API yang mendasarinya yang unik di antara alat Unix: hanya dddapat menimpa atau memotong file di titik mana pun atau mencari dalam file. (Ini adalah ddkemampuan unik, dan ini adalah yang besar; anehnya cukup ddterkenal untuk hal-hal yang dapat dilakukan alat lain.)

  • Sebagian besar alat Unix menimpa file output mereka, yaitu menghapus isinya dan memulainya dari awal. Inilah yang terjadi ketika Anda menggunakan >pengalihan di shell juga.
  • Anda dapat menambahkan konten file dengan >>pengalihan di shell, atau dengan tee -a.
  • Jika Anda ingin mempersingkat file dengan menghapus semua data setelah titik tertentu , ini didukung oleh kernel dan C API yang mendasari melalui truncatefungsi, tetapi tidak diekspos oleh alat baris perintah apa pun kecualidd :

    dd if=/dev/null of=/file/to/truncate seek=1 bs=123456  # truncate file to 123456 bytes
    
  • Jika Anda ingin menimpa data di tengah file, sekali lagi, ini dimungkinkan dalam underyling API dengan membuka file untuk ditulis tanpa memotong (dan memanggil lseekuntuk pindah ke posisi yang diinginkan jika perlu), tetapi hanya dddapat membuka file tanpa memotong atau menambahkan, atau mencari dari shell ( contoh yang lebih kompleks ).

    # 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
    

Jadi ... Sebagai alat sistem, tidak ddada gunanya. Sebagai alat pengolah teks (atau file biner), ini cukup berharga!


Diterima karena saya pikir itu menjelaskan inti dari jawaban lain ( truncdan seekdapat digunakan dari dd).
kizzx2

2
Satu lagi penggunaan khusus: dddapat membaca data biner dari deskriptor file nonseekable tanpa berpotensi menghancurkan data yang belum dibaca karena buffering stdio. Lihat di sini untuk contoh: etalabs.net/sh_tricks.html
R ..

2
@R ..: Ya. Di GNU coreutils 6.10, head -c Npanggilan readdan tidak pernah melampaui N. Dalam NetBSD 5.1, head -cpanggilan getc. Dalam FreeBSD 7.4, head -cpanggilan fread.
Gilles

1
Coreutils ddjuga mengekspos O_DIRECT (dll.) Ke skrip shell, yang menurut saya juga unik.
derobert

1
Coreutils truncatememungkinkan pemotongan atau perluasan file, sehingga menghilangkan penggunaan lain dari dd.
dcoles

22

The ddperintah meliputi BANYAK pilihan yang kucing tidak mampu menampung. Mungkin dalam kasus penggunaan Anda kucing adalah pengganti yang bisa diterapkan, tetapi itu bukan pengganti dd.

Satu contoh akan digunakan dduntuk menyalin bagian dari sesuatu tetapi tidak semuanya. Mungkin Anda ingin merobek beberapa bit dari tengah gambar iso atau tabel partisi dari hard drive berdasarkan lokasi yang diketahui pada perangkat. Dengan ddAnda dapat menentukan opsi mulai, berhenti dan jumlah yang memungkinkan tindakan ini.

Opsi-opsi ini ddmembuatnya sangat diperlukan untuk manipulasi data berbutir halus sedangkan cat* hanya dapat beroperasi pada objek file keseluruhan, perangkat atau stream.

* Seperti dicatat oleh Gilles dalam komentar, dimungkinkan untuk menggabungkan catdengan alat lain untuk mengisolasi bagian dari sesuatu, tetapi catmasih beroperasi pada seluruh objek.


5
ddsebenarnya tidak ada hubungannya dengan perangkat tingkat rendah, perlu masuk /devseperti yang lain. Anda dapat menyalin seluruh partisi dengan cat, atau sebagian dengan tail +c $(($start+1)) | head -c $count.
Gilles

16
Tentu saja. ;-) Dan ketika saya memasukkan disk image 1.6TB ke dalam cat | head | tailuntuk mengambil MB terakhir beberapa disk berputar akan menyedot bulan lebih dekat ke bumi.
Caleb

2
@Gilles Maaf saya memang bermaksud mengakui bahwa saya menggunakan istilah "tingkat rendah" bukan diksi yang sangat baik, meskipun saya mengacu pada data pada perangkat, bukan perangkat. Mungkin "manipulasi data yang disesuaikan" akan lebih baik daripada "memanipulasi data tingkat rendah".
Caleb

21

Belum ada yang menyebutkan bahwa Anda dapat menggunakan dd untuk membuat file jarang , meskipun truncatejuga dapat digunakan untuk tujuan yang sama.

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

Ini hampir instan dan membuat file besar sembarang yang dapat digunakan sebagai file loopback misalnya:

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

Yang menyenangkan adalah bahwa awalnya hanya menggunakan satu blok ruang disk, dan setelah itu tumbuh hanya sesuai kebutuhan (format ext4 dari file 10GB mengkonsumsi 291 MB pada sistem saya). Gunakan duuntuk melihat berapa banyak ruang disk yang sebenarnya digunakan - lshanya melaporkan ukuran maksimum file yang mungkin tumbuh.


4
ls -lsmenunjukkan ukuran yang jarang.
jmtd

2
Perintah Anda menulis byte yang tidak berguna ke file. dd of=sparse-file bs=1 count=0 seek=10Gakan setara dengan truncate -s 10GB sparse-file. Cukup membingungkan, truncatedan ddmemiliki interpretasi yang berlawanan dengan GBvs. G...
frostschutz

5
@ frostschutz: man ddmengatakan: MB =1000*1000, M =1024*1024dan seterusnya. Dan man truncatemengatakan:, MB 1000*1000, M 1024*1024jadi tidak ada perbedaan. Saya menggunakan keduanya dddan truncatedari GNU coreutils. Anda juga harus melakukannya! :-)
erik

@ erik: Terima kasih atas koreksinya. Jika tidak diubah baru-baru ini saya pasti bingung dengan sesuatu yang lain entah bagaimana.
frostschutz

10

Mengganti segmen tertentu dari hard drive dengan sesuatu adalah contoh umum. Misalnya Anda mungkin ingin menghapus MBR Anda menggunakan perintah ini:

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

Anda juga dapat membuat file kosong dengan itu (katakan untuk gambar loop disk):

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

Selain itu, perintah kedua adalah cara tercepat yang saya tahu untuk menggunakan 10MB
Kevin M

3
@ Kevin: Lebih cepat dari head -c? Silakan bagikan tolok ukur !
Gilles

9

ddsangat berguna untuk mencadangkan sektor boot dari hard drive atau perangkat penyimpanan lainnya ( dd if=/dev/sda of=boot_sector.bin bs=512 count=1) dan kemudian menulis ulangnya ( dd if=boot_sector.bin of=/dev/sda). Ini juga berguna untuk membackup header volume yang dienkripsi.

catmungkin bisa diputar untuk melakukan itu tetapi saya tidak akan percaya pada bagian penulisan ulang. Sulit untuk cathanya membaca / menulis sejumlah byte.


5

Saya baru-baru ini memiliki alasan untuk mengkloning beberapa partisi multi-100-of-GB untuk pertama kalinya dalam sejarah linuxing saya (cf cp -aratau rsyncyang telah melayani saya berkali-kali). Tentu saja saya beralih ke dd'karena semua orang tahu itu yang Anda gunakan ... dan terkejut oleh kinerja. Sedikit googling segera membawa saya ke ddrescue, yang saya gunakan beberapa kali sekarang dan bekerja dengan sangat baik (jauh lebih cepat daripada dd).


1
ddrescuesangat bagus, terutama untuk mengeluarkan data dari disk yang rusak.
ryenus

5

Berikut adalah beberapa trik yang saya buat selama bertahun-tahun ..

Potong-dan-Tempel di bash mode tty atau non-interaktif

Jika Anda berada dalam situasi di mana EOF / ^ D / ^ F tidak terdeteksi, Anda dapat menggunakan dd untuk mentransfer file teks ke host. Karena itu akan berhenti membaca setelah jumlah byte yang ditentukan secara otomatis.

Saya menggunakan ini baru-baru ini tahun lalu selama latihan keamanan di mana kami bisa mendapatkan kerang non-tty pada host jarak jauh dan diperlukan untuk mentransfer file.

Bahkan, saya bahkan melakukan beberapa file biner dengan base64 mengkodekannya dan menggunakan script decoding pure-bash base64 murni yang lambat.

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

Trik yang sangat keren adalah ketika dd sedang berjalan, jika Anda mengirimkan sinyal USR1, itu akan memancarkan statusnya saat ini (byte dibaca, byte per detik ..)

Filter state throughput universal

Saya menulis ini untuk bertindak sebagai filter kemajuan bash murni untuk setiap program yang memancarkan data melalui stdout. (Catatan: Hampir semua hal akan memancarkan data melalui stdout - untuk program yang tidak, Anda dapat menipu jika mereka tidak menganggap Anda menggunakan / dev / stdout sebagai nama file. Tapi idenya pada dasarnya, setiap kali Anda mendapatkan X jumlah byte, cetak tanda pagar (seperti FTP sekolah lama saat mode hash Anda aktif)

(Catatan) Berkas progresnya payah, ini sebagian besar merupakan bukti konsep. Jika saya redid, saya hanya akan menggunakan variabel.

 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

file irisan-dan-dadu menggunakan file menangani shell anonim

Berikut adalah contoh kode pseudo-sangat tentang bagaimana Anda dapat memiliki file tar yang ditandatangani yang dapat Anda ekstrak tanpa kesalahan dengan memberikan input tar melalui penanganan file anonim - tanpa menggunakan file tmp apa pun untuk menyimpan data file parsial.

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})

Tl; dr adalah: Saya merasa sangat berguna. Dan ini hanya tiga contoh yang bisa saya pikirkan dari atas kepala saya.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.