Saya memiliki file 1 TB. Saya ingin membaca dari byte 12345678901 ke byte 19876543212 dan meletakkannya pada output standar pada mesin dengan 100 MB RAM.
Saya dapat dengan mudah menulis skrip perl yang melakukan ini. sysread menghasilkan 700 MB / s (baik-baik saja), tetapi syswrite hanya menghasilkan 30 MB / s. Saya ingin sesuatu yang lebih efisien, lebih disukai sesuatu yang diinstal setiap sistem Unix dan dapat memberikan dalam urutan 1 GB / s.
Ide pertama saya adalah:
dd if=1tb skip=12345678901 bs=1 count=$((19876543212-12345678901))
Tapi itu tidak efisien.
Edit:
Saya tidak tahu bagaimana saya mengukur syswrite salah. Ini menghasilkan 3,5 GB / s:
perl -e 'sysseek(STDIN,shift,0) || die; $left = shift; \
while($read = sysread(STDIN,$buf, ($left > 32768 ? 32768 : $left))){ \
$left -= $read; syswrite(STDOUT,$buf);
}' 12345678901 $((19876543212-12345678901)) < bigfile
dan menghindari yes | dd bs=1024k count=10 | wc
mimpi buruk.
bs=1M iflag=skip_bytes,count_bytes
Jawaban:
Ini lambat karena ukuran blok kecil. Menggunakan GNU terbaru
dd
( coreutils v8.16 + ), cara paling sederhana adalah dengan menggunakan opsiskip_bytes
dancount_bytes
:Memperbarui
fullblock
opsi ditambahkan di atas sesuai jawaban @Gilles . Pada awalnya saya berpikir bahwa itu mungkin tersirat olehcount_bytes
, tetapi ini tidak terjadi.Masalah yang disebutkan adalah masalah potensial di bawah ini, jika
dd
panggilan baca / tulis terputus karena alasan apa pun maka data akan hilang. Ini tidak mungkin dalam kebanyakan kasus (kemungkinan berkurang karena kita membaca dari file dan bukan pipa).Menggunakan opsi
dd
tanpaskip_bytes
dancount_bytes
lebih sulit:Anda juga bisa bereksperimen dengan ukuran blok yang berbeda, tetapi keuntungannya tidak akan terlalu dramatis. Lihat - Apakah ada cara untuk menentukan nilai optimal untuk parameter bs ke dd?
sumber
bs
bukan merupakan faktorskip
?skip
sejumlah blok, bukan byte. Mungkin Anda bingung karenaskip_bytes
digunakan pada contoh pertama artinyaskip
ada dalam byte di sana?bs
adalah Anda4,096
, yang berarti Anda tidak dapat melewati4,096
byte dengan lebih akuratdd
dengan menggunakan pertama dan terakhirbs=1
untuk menyalin data yang tidak memulai atau selesai pada blok alignment.bs=1
memberitahudd
untuk membaca dan menulis satu byte pada suatu waktu. Ada overhead untuk masing-masingread
danwrite
panggilan, yang membuat ini lambat. Gunakan ukuran blok yang lebih besar untuk kinerja yang layak.Ketika Anda menyalin seluruh file, setidaknya di Linux, saya telah menemukan itu
cp
dancat
lebih cepat daripadadd
, bahkan jika Anda menentukan ukuran blok yang besar.Untuk menyalin hanya sebagian file, Anda dapat
tail
memasukkan kehead
. Ini membutuhkan GNU coreutils atau implementasi lain yang harushead -c
menyalin sejumlah byte tertentu (tail -c
ada dalam POSIX tetapihead -c
tidak). Patokan cepat di Linux menunjukkan ini lebih lambat daripadadd
, mungkin karena pipa.Masalahnya
dd
adalah bahwa itu tidak dapat diandalkan: ia dapat menyalin sebagian data . Sejauh yang saya tahu,dd
apakah aman saat membaca dan menulis ke file biasa - lihat Kapan dd cocok untuk menyalin data? (atau, ketika dibaca () dan tulis () parsial) - tetapi hanya selama itu tidak terganggu oleh sinyal . Dengan GNU coreutils, Anda dapat menggunakanfullblock
flag, tetapi ini tidak portabel.Masalah lainnya
dd
adalah sulit untuk menemukan jumlah blok yang berfungsi, karena jumlah byte yang dilewati dan jumlah byte yang ditransfer harus berupa kelipatan dari ukuran blok. Anda dapat menggunakan beberapa panggilan untukdd
: satu untuk menyalin blok parsial pertama, satu untuk menyalin sebagian besar blok yang selaras dan satu untuk menyalin blok parsial terakhir - lihat jawaban Graeme untuk cuplikan shell. Tetapi jangan lupa bahwa Anda ketika Anda menjalankan skrip, kecuali jika Anda menggunakanfullblock
bendera, Anda harus berdoa agar itudd
akan menyalin semua data.dd
mengembalikan status bukan nol jika salinannya parsial, sehingga mudah untuk mendeteksi kesalahan, tetapi tidak ada cara praktis untuk memperbaikinya.POSIX tidak ada yang lebih baik untuk ditawarkan di level shell. Saran saya adalah menulis sebuah program C tujuan-kecil khusus (tergantung pada apa yang Anda terapkan, Anda dapat menyebutnya
dd_done_right
atautail_head
ataumini-busybox
).sumber
yes | dd bs=1024k count=10 | wc
masalahnya sebelumnya. Menjijikan.Dengan
dd
:Atau dengan
losetup
:Dan kemudian
dd
,,cat
... perangkat loop.sumber
Ini adalah bagaimana Anda melakukannya, Anda bisa melakukan ini:
Itu semua yang benar-benar diperlukan - tidak memerlukan lebih banyak Di tempat pertama
dd count=0 skip=1 bs=$block_size1
akanlseek()
lebih dari input file biasa praktis instan. Tidak ada peluang data yang terlewat atau apa pun yang tidak benar lainnya diberitahu tentang hal itu, Anda bisa mencari langsung ke posisi awal yang Anda inginkan. Karena deskriptor file dimiliki oleh shell dandd
itu hanya mewarisinya, mereka akan mempengaruhi posisi kursornya dan jadi Anda bisa mengambilnya dalam langkah-langkah. Ini sangat sederhana - dan tidak ada alat standar yang lebih cocok untuk tugas itudd
.Itu menggunakan 64k blocksize yang sering ideal. Berlawanan dengan kepercayaan populer, pemblokiran yang lebih besar tidak membuat
dd
pekerjaan lebih cepat. Di sisi lain, buffer kecil juga tidak bagus.dd
perlu menyinkronkan waktunya dalam panggilan sistem sehingga tidak perlu menunggu menyalin data ke dalam memori dan keluar lagi, tetapi juga agar tidak perlu menunggu panggilan sistem. Jadi, Anda ingin mengambil waktu yang cukup berikutnyaread()
tidak harus menunggu pada yang terakhir, tetapi tidak terlalu banyak sehingga Anda buffering dalam ukuran yang lebih besar daripada yang diperlukan.Jadi yang pertama
dd
lompat ke posisi awal. Itu membutuhkan nol waktu. Anda dapat memanggil program lain yang Anda suka pada saat itu untuk membaca stdin-nya dan akan mulai membaca langsung di byte byte yang Anda inginkan. Saya memanggil orang laindd
untuk membaca((interval / blocksize) -1)
blok hitungan ke stdout.Hal terakhir yang diperlukan adalah menyalin modulus (jika ada) dari operasi divisi sebelumnya. Dan itu saja.
Omong-omong, jangan percaya ketika orang menyatakan fakta di wajah mereka tanpa bukti. Ya, dimungkinkan untuk
dd
melakukan pembacaan singkat (meskipun hal-hal seperti itu tidak mungkin ketika membaca dari perangkat blok yang sehat - demikian namanya) . Hal-hal seperti itu hanya mungkin jika Anda tidak benar bufferdd
aliran yang dibaca dari selain perangkat blok. Sebagai contoh:Dalam kedua kasus
dd
menyalin semua data. Dalam kasus pertama adalah mungkin (meskipun tidak mungkin dengancat
) beberapa blok keluaran yangdd
menyalin akan menggigit sama dengan "$ num" byte karenadd
ditentukan hanya untuk buffer apa saja ketika buffer secara khusus diminta pada perintahnya- baris.bs=
merupakan maksimum blok-ukuran karena tujuan daridd
adalah real-time i / o.Dalam contoh kedua saya secara eksplisit menentukan keluaran blocksize dan
dd
buffer membaca hingga penulisan lengkap dapat dilakukan. Itu tidak mempengaruhicount=
yang didasarkan pada blok input, tetapi untuk itu Anda hanya perlu yang laindd
. Setiap informasi yang salah yang diberikan kepada Anda sebaliknya harus diabaikan.sumber