Cách nhanh nhất để nối các tệp


25

Tôi đã có 10k + tệp có tổng cộng hơn 20 GB mà tôi cần ghép thành một tệp.

Có cách nào nhanh hơn

cat input_file* >> out

?

Cách ưa thích sẽ là lệnh bash, Python cũng được chấp nhận nếu không chậm hơn đáng kể.


Đã cập nhật câu trả lời của tôi, findkhông sắp xếp các tệp giống như shell toàn cầu.
Graeme

5
Bất kỳ và tất cả các giải pháp (lành mạnh) sẽ có tốc độ tương đương ở đây vì thời gian sẽ là 99% I / O hệ thống.
goldilocks


3
Xem xét việc viết tệp được nối vào một đĩa khác với tệp bạn đang đọc.
Luis

1
Nó sẽ nhanh hơn nếu outnằm trên một đĩa khác.

Câu trả lời:


30

Không, mèo chắc chắn là cách tốt nhất để làm điều này. Tại sao sử dụng python khi có một chương trình đã được viết bằng C cho mục đích này? Tuy nhiên, tuy nhiên, bạn có thể muốn xem xét sử dụng xargstrong trường hợp chiều dài dòng lệnh vượt quá ARG_MAXvà bạn cần nhiều hơn một cat. Sử dụng các công cụ GNU, điều này tương đương với những gì bạn đã có:

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z |
  xargs -0 cat -- >>out

1
Bạn có thể đảm bảo trong trường hợp này rằng các tập tin của bạn sẽ được đọc theo thứ tự?
Kiwy

1
Có, bởi vì đầu ra của findđược dẫn qua sort. Nếu không có điều này, các tệp sẽ được liệt kê theo thứ tự tùy ý (được xác định bởi hệ thống tệp, có thể là thứ tự tạo tệp).
ngày

@scai Tôi xin lỗi, xin lỗi, khá rõ ràng
Kiwy

1
@Kiwy, trường hợp duy nhất tôi có thể thấy là nếu miền địa phương không được đặt đúng trong môi trường, thì sắp xếp có thể hành xử khác với toàn bashcầu. Mặt khác, tôi không thấy bất kỳ trường hợp nào xargshoặc catsẽ không cư xử như mong đợi.
Graeme

3
@MarcvanLeeuwen, xargssẽ gọi khi có thể catđể tránh lỗi E2BIG của lệnh thực thi (2).
Stéphane Chazelas

21

Phân bổ không gian cho tệp đầu ra trước tiên có thể cải thiện tốc độ chung vì hệ thống sẽ không phải cập nhật phân bổ cho mỗi lần ghi.

Chẳng hạn, nếu trên 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

Một lợi ích khác là nếu không có đủ không gian trống, bản sao sẽ không được thử.

Nếu bật btrfs, bạn có thể copy --reflink=alwaystệp đầu tiên (ngụ ý không có bản sao dữ liệu và do đó sẽ gần như tức thời) và nối thêm phần còn lại. Nếu có 10000 tệp, điều đó có lẽ sẽ không tạo ra nhiều khác biệt trừ khi tệp đầu tiên rất lớn.

Có một API để khái quát hóa rằng sao chép lại tất cả các tệp (nhưng BTRFS_IOC_CLONE_RANGE ioctl), nhưng tôi không thể tìm thấy bất kỳ tiện ích nào hiển thị API đó, vì vậy bạn phải thực hiện bằng C ( pythonhoặc các ngôn ngữ khác với điều kiện họ có thể gọi tùy ý ioctl) .

Nếu các tệp nguồn thưa thớt hoặc có các chuỗi ký tự NUL lớn, bạn có thể tạo một tệp đầu ra thưa thớt (tiết kiệm thời gian và dung lượng ổ đĩa) bằng (trên các hệ thống GNU):

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out

1
@XTian, không có, nó phải là không >hay >>, nhưng 1<>như tôi đã nói để viết vào tập tin.
Stéphane Chazelas

5
@grebneke, <>là toán tử chuyển hướng đọc / ghi tiêu chuẩn Bourne / POSIX. Xem hướng dẫn sử dụng shell của bạn hoặc thông số POSIX để biết chi tiết. Mặc định fd0dành cho <>toán tử ( <>viết tắt của từ 0<>, thích <là viết tắt 0<>viết tắt 1>), vì vậy bạn cần 1chuyển hướng rõ ràng thiết bị xuất chuẩn. Ở đây, không quá nhiều đến mức chúng ta cần đọc + write ( O_RDWR), nhưng chúng ta không muốn O_TRUNC(như trong >) sẽ giải quyết những gì chúng ta vừa phân bổ.
Stéphane Chazelas

1
@grebneke, unix.stackexchange.com/search?q=user%3A22565+%22%3C%3E%22 sẽ cung cấp cho bạn một vài thứ. ksh93 đã tìm kiếm các nhà khai thác BTW và bạn có thể tìm kiếm chuyển tiếp bằng ddhoặc thông qua việc đọc.
Stéphane Chazelas

1
@StephaneChazelas - cảm ơn rất nhiều, sự giúp đỡ và kiến ​​thức của bạn được đánh giá cao!
grebneke

1
Tôi không tin rằng sẽ có nhiều trường hợp fallocatesẽ phủ nhận chi phí phụ find, mặc dù nó sẽ nhanh hơn trong lần thứ hai. btrfschắc chắn mở ra một số khả năng thú vị mặc dù.
Graeme
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.