dd: beberapa file input

13

Saya perlu menyatukan potongan dari dua file:

jika saya perlu menggabungkan seluruh file, saya bisa melakukannya

cat file1 file2 > output

Tapi saya harus melewati 1MB pertama dari file pertama, dan saya hanya ingin 10 MB dari file kedua. Kedengarannya seperti pekerjaan dd.

dd if=file1 bs=1M count=99 skip=1 of=temp1
dd if=file2 bs=1M count=10 of=temp2
cat temp1 temp2 > final_output

Apakah ada kemungkinan untuk melakukan ini dalam satu langkah? yaitu, tanpa perlu menyimpan hasil antara? Bisakah saya menggunakan beberapa file input dd?

Martin Vegter
sumber

Jawaban:

21

dd dapat menulis ke stdout juga.

( dd if=file1 bs=1M count=99 skip=1
  dd if=file2 bs=1M count=10  ) > final_output
meuh
sumber
Ini mungkin cara terbaik. File output tidak ditutup / dibuka kembali (seperti itu dengan oflag=append conv=notrunc), sehingga filesystem yang melakukan alokasi tertunda (seperti XFS) paling mungkin untuk memutuskan file selesai ditulis ketika masih ada lagi yang harus dilakukan.
Peter Cordes
@PeterCordes itu adalah poin yang bagus, tetapi selama ddtidak diminta sync, alokasi yang tertunda seharusnya tidak langsung masuk (kecuali jika memori ketat dalam hal ini, tidak ada metode yang akan menunda alokasi).
Stephen Kitt
@StephenKitt: Anda mungkin benar. Saya sedang memikirkan preallokasi spekulatif XFS , di mana ia perlu secara khusus mendeteksi pola akses tutup / buka kembali (kadang-kadang terlihat untuk file log).
Peter Cordes
3
Dalam shell seperti bashdan mkshyang tidak mengoptimalkan garpu untuk perintah terakhir dalam subkulit, Anda dapat membuatnya sedikit lebih efisien dengan mengganti subkulit dengan grup perintah. Untuk cangkang lain, seharusnya tidak masalah, dan pendekatan subkulit bahkan mungkin sedikit lebih efisien karena cangkang tidak perlu menyimpan dan mengembalikan stdout.
Stéphane Chazelas
10

Saya tidak berpikir Anda dapat dengan mudah membaca banyak file dalam satu ddpermintaan, tetapi Anda dapat menambahkan untuk membangun file output dalam beberapa langkah:

dd if=file1 bs=1M count=99 skip=1 of=final_output
dd if=file2 bs=1M count=10 of=final_output oflag=append conv=notrunc

Anda harus menentukan keduanya conv=notruncdan oflag=append. Yang pertama menghindari pemotongan output, yang kedua mulai menulis dari akhir file yang ada.

Stephen Kitt
sumber
8

Ingatlah bahwa itu ddadalah antarmuka mentah ke read(), write()dan lseek()system call. Anda hanya dapat menggunakannya dengan andal untuk mengekstrak potongan data dari file biasa, perangkat blok dan beberapa perangkat karakter (seperti /dev/urandom), yaitu file yang read(buf, size)dijamin akan kembali sizeselama akhir file tidak tercapai.

Untuk pipa, soket, dan sebagian besar perangkat karakter (seperti ttys), Anda tidak memiliki jaminan seperti itu kecuali Anda melakukan read()ukuran 1, atau menggunakan ddekstensi GNU iflag=fullblock.

Jadi:

{
  gdd < file1 bs=1M iflag=fullblock count=99 skip=1
  gdd < file2 bs=1M iflag=fullblock count=10
} > final_output

Atau:

M=1048576
{
  dd < file1 bs=1 count="$((99*M))" skip="$M"
  dd < file2 bs=1 count="$((10*M))"
} > final_output

Atau dengan cangkang dengan dukungan bawaan untuk operator pencari seperti ksh93:

M=1048576
{
  command /opt/ast/bin/head -c "$((99*M))" < file1 <#((M))
  command /opt/ast/bin/head -c "$((10*M))" < file2
}

Atau zsh(dengan asumsi Anda headmendukung -copsi di sini):

zmodload zsh/system &&
{
  sysseek 1048576 && head -c 99M &&
  head -c 10M < file2
} < file1 > final_output
Stéphane Chazelas
sumber
Apakah Anda benar-benar membutuhkan penawaran? Apakah hasilnya selalu berupa bilangan bulat?
Steven Penny
@StevenPenny, membiarkan ekspansi tanpa tanda kutip meminta shell untuk membagi + glob yang tidak masuk akal di sini. Bagian split dilakukan pada nilai saat ini dari $IFS. Itu terlepas dari isi variabel / ekspansi. Lihat juga Implikasi keamanan dari lupa mengutip variabel dalam bash / POSIX shells
Stéphane Chazelas
@ Stéphane Chazelas - pada contoh pertama, Anda menggunakan gddsebagai ganti dd. Apakah itu salah ketik, atau disengaja?
Martin Vegter
3

Dengan isme bash , dan "penggunaan kucing yang tidak berguna" secara fungsional , tetapi paling dekat dengan sintaks yang digunakan OP:

cat <(dd if=file1 bs=1M count=99 skip=1) \
    <(dd if=file2 bs=1M count=10) \
   > final_output

(Dikatakan demikian, jawaban Stephen Kitt tampaknya merupakan metode yang paling efisien .)

agc
sumber
3
Sebenarnya, <(...)adalah kshisme yang keduanya zshdan bashdisalin.
Stéphane Chazelas