Tại sao việc di chuyển một số tệp trong một thư mục mất nhiều thời gian hơn là di chuyển toàn bộ thư mục?


21

Tôi có hàng triệu hình ảnh trên máy chủ đám mây ubfox của mình. Khi tôi di chuyển một thư mục hoàn chỉnh chứa 12 triệu hình ảnh bằng mvlệnh, nó sẽ xảy ra gần như ngay lập tức. Tuy nhiên, khi tôi mvchỉ hình ảnh (không phải thư mục) thì phải mất một thời gian. Có cách nào để di chuyển tất cả các hình ảnh nhanh như thư mục không?

Đây là những gì đang xảy ra:

  1. thư mục src có 12 triệu hình ảnh và tôi chuyển nó sang thư mục dst bằng

    $ mv  src ../dst
    

    Xảy ra ngay lập tức

  2. Trong thư mục src tôi làm điều này để di chuyển:

    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ {} +
    

    Điều này cần một chút thời gian.

Có cách nào để tăng tốc quá trình thứ hai không?


1
Không phải là một giải pháp - nhưng để làm rõ: cmd2 phải chậm hơn cmd1 vì nó đang sử dụng find và sau đó thực hiện di chuyển cho kết quả. Điều này không bao giờ có thể nhanh như một động thái trực tiếp mà không cần tìm trước quá trình.
dufte

có lẽ dstlà trong một phân vùng trong khi đó ../../dstlà trên một phân vùng khác.
phuclv

Như đã viết, điều này thậm chí không giống như một lời mời tìm hợp lệ. Nó không có bất kỳ {}đối số nào trong đó tên tệp sẽ được mở rộng.
R ..

Tôi đã gửi một bản chỉnh sửa làm thay đổi tiêu đề, xóa tham chiếu đến "hình ảnh" và thay thế nó bằng nội dung của vấn đề - đó là di chuyển các tệp riêng lẻ so với di chuyển toàn bộ thư mục. Tôi hy vọng nó được chấp nhận bởi một người có đại diện để làm điều đó.
Monty Harder

1
Nó không phải là một lời mời hợp lệ của find. find ... -exec mv -t ../../dst/ {} \;sẽ gọi mvmột lần cho mỗi tệp; find ... -exec mv -t ../../dest {} +sẽ nhanh hơn nhiều, sao chép càng nhiều tệp trên mỗi cuộc gọi càng tốt, nhưng vẫn không nhanh bằng việc di chuyển thư mục như được giải thích bởi Dadexix86 .
chepner

Câu trả lời:


50

TL; DR : Không

Đối với số lượng tệp nhỏ hơn, bạn sẽ không cần findnhưng ngay cả trong trường hợp đơn giản và nhỏ hơn này, nếu bạn chỉ

mv *.jpg ../../dst/

sẽ mất nhiều thời gian hơn là di chuyển toàn bộ thư mục cùng một lúc.


Tại sao? Vấn đề là phải hiểu những gì mv.

Nói ngắn gọn, mvdi chuyển một số (xác định một thư mục hoặc một tệp) từ một nút (thư mục chứa nó) sang một số khác và các chỉ số này được cập nhật trong nhật ký của hệ thống tệp hoặc trong FAT (nếu hệ thống tệp được thực hiện theo cách như vậy).

Nếu nguồn và đích nằm trên cùng một hệ thống tệp, không có chuyển động dữ liệu thực tế, nó chỉ thay đổi vị trí, điểm mà chúng được gắn vào.

Vì vậy, khi bạn mv một thư mục, bạn đang thực hiện thao tác này một lần .

Nhưng khi bạn di chuyển 1 triệu tệp, bạn đang thực hiện thao tác này 1 triệu lần .

Để cho bạn một ví dụ thực tế, bạn có một cây có nhiều nhánh. Đặc biệt, có một nút mà 1 triệu chi nhánh được đính kèm.
Để cắt các nhánh này và di chuyển chúng đến một nơi khác, bạn có thể cắt từng nhánh trong số chúng, để bạn thực hiện 1 triệu lần cắt hoặc bạn cắt ngay trước nút, do đó chỉ thực hiện một lần cắt (đây là sự khác biệt giữa việc di chuyển tệp và cac thu mục).


4
Bạn nên bao gồm rằng một mvtrên cùng một hệ thống tập tin chỉ là viết lại mục TOC.
Videonauth

Tôi không chắc rằng tôi hiểu ý của bạn bởi TOC. Theo như tôi biết, không có bảng nào trong các hệ thống tệp ext, hoặc NTFS, hoặc btrfs, v.v. FAT có một bảng (từ đó lấy tên) nhưng ví dụ, ext lưu tên và khối, và cha mẹ, trẻ em và các thông tin khác trong các nút. Nếu bạn có thể chỉ cho tôi một số tài liệu tham khảo nơi được giải thích thì ext FS có TOC của họ và nó được sử dụng để làm gì, tôi sẽ vui lòng đọc và cập nhật câu trả lời :)
Dadexix86

10
Ừm. mv *.jpgcó khả năng thất bại trong 12 triệu tệp, đó là lý do tại sao anh ta sử dụng find. Hầu hết các Unix, Linux bao gồm tôi tin (trừ khi ai đó thay đổi nó trong 5-10 năm qua) có độ dài tối đa của dòng lệnh. Tôi nghĩ rằng đó là 64K cho Linux trong một thời gian dài. Giới hạn tương tự áp dụng cho các biến môi trường, tôi khá chắc chắn.
Zan Lynx

1
Di chuyển một tập tin là nhiều hơn về việc di chuyển tên của nó . Các mục thư mục giống như Unix chứa tên tệp và số inode, về cơ bản là một con trỏ tới phần còn lại của siêu dữ liệu. Một thư mục chỉ là một loại tập tin đặc biệt. Bản thân inode không chứa dữ liệu thực tế của tệp, chỉ trỏ đến nó, do đó, có một chút sai lầm khi nói rằng bất cứ điều gì được di chuyển từ một nút. Mặt khác, các tạp chí hệ thống tệp thường đề cập đến một loại nhật ký siêu dữ liệu chủ yếu được sử dụng để chống sự cố.
ilkkachu

1
Tất nhiên, thuật ngữ không phải là điểm chính ở đây. Điều quan trọng là chính xác những gì bạn đã nói: bên trong một hệ thống tập tin, một động thái chỉ cần chạm vào siêu dữ liệu. Từ hệ thống tệp này sang hệ thống tệp khác, không có phím tắt và tất cả các tệp cần được di chuyển (tái tạo) từng cái một, bao gồm cả nội dung của chúng. Trong trường hợp đó, không vấn đề gì nếu một người di chuyển toàn bộ thư mục hoặc chỉ các tệp bên trong, nó sẽ chậm như vậy.
ilkkachu

13

Nó vẫn sẽ chậm bởi vì, như đã lưu ý, hệ thống tệp phải đặt lại từng tên tệp vào vị trí mới.

Tuy nhiên, bạn có thể tăng tốc nó từ những gì bạn có bây giờ.

Lệnh find của bạn chạy exec một lần cho mỗi tệp. Vì vậy, nó khởi chạy mvlệnh 12 triệu lần cho 12 triệu tệp. Điều này có thể được cải thiện theo hai cách.

  • Thêm một điểm cộng vào cuối:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    Kiểm tra trang man để đảm bảo nó được hỗ trợ trong phiên bản của bạn find. Hiệu quả sẽ là chạy một loạt các mvlệnh với càng nhiều tên tệp sẽ phù hợp với từng dòng lệnh.

  • Sử dụng findxargscùng nhau.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    Các -print0sẽ sử dụng NUL, aka zero byte để tách các tên tập tin. Điều này cộng với xargs -0sửa chữa bất kỳ vấn đề xargsnào khác có không gian trong tên tệp. Các xargslệnh sẽ đọc danh sách các tên tập tin từ findlệnh và chạy mvlệnh trên nhiều tên tập tin như sẽ phù hợp.


7

Sự nhầm lẫn của bạn xuất phát từ sự trừu tượng của hệ thống tệp khiến bạn tin rằng một thư mục chứa các tệp và các thư mục khác theo kiểu giống như cây. Điều này không thực sự đúng: tất cả các tệp và thư mục trong một hệ thống tệp được đặt ở cùng cấp độ và được xác định bằng một số loại, tùy thuộc vào việc thực hiện. Thư mục chỉ là các tệp đặc biệt chứa danh sách các tệp khác.

Khi bạn "di chuyển" các tệp trong một hệ thống tệp, các tệp thực tế sẽ không đi bất cứ đâu. Thay vào đó, danh sách bên trong các thư mục được cập nhật để phản ánh sự thay đổi.

mv src ../dstdi chuyển một mục nhập danh sách từ thư mục này .sang thư mục khác ../dst, vì vậy nó rất nhanh.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/phải di chuyển hàng triệu mục, vì vậy nó chậm hơn. Nó có khả năng được tăng tốc nếu bạn mvchỉ gọi một lần và không một lần cho mỗi tệp và mvchính lệnh có thể được tối ưu hóa để di chuyển một số mục trong thư mục trong một bước, nhưng không có cách nào để thực hiện nhanh như khi bạn di chuyển một thư mục .


4

Một câu trả lời đơn giản

di chuyển một tập tin được thực hiện là 3 bước:

  • thêm () một liên kết đến tệp vào danh sách inode của thư mục đích
  • kiểm tra xem liên kết đã được thêm thành công chưa
  • xóa () liên kết khỏi danh sách các nút của thư mục nguồn nếu kiểm tra ở trên thành công.

quá trình này là giống nhau cho một tập tin hoặc một thư mục.
và rõ ràng làm điều này cho 1 tệp nhanh hơn 100 so với làm 100 tệp.

man link là add ()
man unlinklà remove ()
mvchỉ sử dụng hai lệnh trên và thêm kiểm tra ở giữa để tránh mất dữ liệu.


1
Vâng, cũng có đổi tên ().
ilkkachu
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.