Cara tercepat untuk menggabungkan file

25

Saya punya 10k + file dengan total lebih dari 20GB yang harus saya gabungkan menjadi satu file.

Apakah ada cara yang lebih cepat daripada

cat input_file* >> out

?

Cara yang disukai adalah perintah bash, Python juga dapat diterima jika tidak terlalu lambat.

fsperrle
sumber
Diperbarui jawaban saya, findtidak mengurutkan file sama dengan shell glob.
Graeme
5
Setiap dan semua (waras) solusi akan memiliki kecepatan yang setara di sini karena waktu akan 99% sistem I / O.
goldilocks
3
Mempertimbangkan menulis file gabungan dalam disk yang berbeda dari yang Anda baca.
Luis
1
Akan lebih cepat jika outterletak di disk lain.

Jawaban:

30

Tidak, kucing pasti cara terbaik untuk melakukan ini. Mengapa menggunakan python ketika ada program yang sudah ditulis dalam C untuk tujuan ini? Namun, Anda mungkin ingin mempertimbangkan untuk menggunakan xargsjika panjang baris perintah melebihi ARG_MAXdan Anda membutuhkan lebih dari satu cat. Menggunakan alat GNU, ini setara dengan apa yang sudah Anda miliki:

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z |
  xargs -0 cat -- >>out
Graeme
sumber
1
Bisakah Anda memastikan dalam hal ini bahwa file Anda akan dibaca dalam urutan?
Kiwy
1
Ya, karena output finddisalurkan melalui sort. Tanpa ini, file akan terdaftar dalam urutan sewenang-wenang (ditentukan oleh sistem file, yang bisa menjadi urutan pembuatan file).
scai
@scai Saya salah membaca maaf, dengan semacam itu cukup jelas
Kiwy
1
@ Kyiwy, satu-satunya kasus yang bisa saya lihat adalah jika lokal tidak diatur dengan benar di lingkungan, maka sort mungkin berperilaku berbeda dari bashbola dunia. Kalau tidak, saya tidak melihat kasus di mana xargsatau cattidak akan berperilaku seperti yang diharapkan.
Graeme
3
@MarcvanLeeuwen, xargsakan memanggil sesering mungkin catuntuk menghindari kesalahan eksekusi E2BIG (2).
Stéphane Chazelas
21

Mengalokasikan ruang untuk file output terlebih dahulu dapat meningkatkan kecepatan keseluruhan karena sistem tidak perlu memperbarui alokasi untuk setiap penulisan.

Misalnya, jika di Linux:

size=$({ find . -maxdepth 1 -type f -name 'input_file*' -printf '%s+'; echo 0;} | bc)
fallocate -l "$size" out &&
  find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat 1<> out

Manfaat lain adalah bahwa jika tidak ada cukup ruang kosong, salinan tidak akan dicoba.

Jika aktif btrfs, Anda dapat copy --reflink=alwaysmenggunakan file pertama (yang tidak mengandung salinan data dan karena itu akan hampir instan), dan menambahkan sisanya. Jika ada 10.000 file, itu mungkin tidak akan membuat banyak perbedaan meskipun kecuali file pertama sangat besar.

Ada API untuk menggeneralisasi itu untuk menyalin ulang semua file (the BTRFS_IOC_CLONE_RANGE ioctl), tapi saya tidak dapat menemukan utilitas yang mengekspos API itu, jadi Anda harus melakukannya dalam C (atau pythonatau bahasa lain asalkan mereka dapat memanggil ioctls sewenang-wenang ) .

Jika file sumber jarang atau memiliki urutan besar karakter NUL, Anda bisa membuat file output jarang (menghemat waktu dan ruang disk) dengan (pada sistem GNU):

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out
Stéphane Chazelas
sumber
1
@XTian, ​​tidak, seharusnya tidak >juga >>, tetapi 1<>seperti yang saya katakan untuk menulis ke dalam file.
Stéphane Chazelas
5
@ grebneke, <>adalah operator redirection read + write Bourne / POSIX standar. Lihat manual shell Anda atau spesifikasi POSIX untuk detailnya. Defaultnya fdadalah 0untuk <>operator ( <>kependekan dari 0<>, suka <adalah kependekan 0<dan >kependekan dari 1>), jadi Anda perlu 1untuk secara langsung mengarahkan stdout. Di sini, kita tidak perlu membaca + tulis ( O_RDWR), tetapi kita tidak menginginkan O_TRUNC(seperti pada >) yang akan membatalkan alokasi yang baru saja kita alokasikan.
Stéphane Chazelas
1
@grebneke, unix.stackexchange.com/search?q=user%3A22565+%22%3C%3E%22 akan memberi Anda beberapa. ksh93 telah mencari operator BTW, dan Anda dapat mencari maju dengan ddatau melalui membaca.
Stéphane Chazelas
1
@StephaneChazelas - terima kasih banyak, bantuan dan pengetahuan Anda sangat dihargai!
grebneke
1
Saya tidak yakin bahwa akan ada banyak kasus di mana fallocateakan meniadakan overhead tambahan find, meskipun akan lebih cepat pada putaran kedua. btrfstentu membuka beberapa kemungkinan menarik.
Graeme