Có gì nhanh hơn `tìm. | wc -l` để đếm tập tin trong một thư mục?


8

Không có gì lạ khi tôi phải đếm số lượng tệp trong một thư mục, đôi khi điều này chạy vào hàng triệu.

Có cách nào tốt hơn là chỉ liệt kê và đếm chúng find . | wc -lkhông? Có một số loại cuộc gọi hệ thống tập tin mà bạn có thể thực hiện trên ext3 / 4 mà ít I / O hơn?


3
Bạn đang đếm không chỉ các tập tin, mà cả các thư mục. Nếu bạn chỉ muốn đếm các tệp, hãy sử dụng "find. -Ape f | wc -l" nếu bạn muốn đếm các liên kết tượng trưng và các tệp thông thường, hãy sử dụng "find.
-Ape f -or

Một thư mục là một loại tập tin, cũng như các thiết bị, liên kết tượng trưng và ổ cắm. Các tập tin thông thường là một tập hợp con của các tập tin.
Toby Speight

1
Ví dụ bạn đưa ra gợi ý rằng bạn muốn có một số đệ quy - nếu không, thì bạn cần find -maxdepth 1. Lưu ý rằng với cách tiếp cận hiện tại của bạn, bạn sẽ đếm gấp đôi bất kỳ tên nào có chứa ký tự dòng mới.
Toby Speight

Câu trả lời:


13

Không phải là tăng tốc cơ bản nhưng ít nhất là một cái gì đó :)

find . -printf \\n | wc -l

Bạn thực sự không cần phải vượt qua danh sách tên tệp, chỉ cần các dòng mới là đủ. Biến thể này nhanh hơn khoảng 15% trên Ubuntu 12.04.3 của tôi khi các thư mục được lưu trong bộ nhớ cache. Ngoài ra, biến thể này sẽ hoạt động chính xác với tên tệp chứa dòng mới.

Điều thú vị là biến thể này có vẻ chậm hơn một chút so với biến thể ở trên:

find . -printf x | wc -c

Trường hợp đặc biệt - nhưng thực sự nhanh

Nếu thư mục nằm trên hệ thống tệp riêng của nó, bạn chỉ cần đếm các nút:

df -i .

Nếu số lượng thư mục và tệp trong các thư mục khác không được thay đổi nhiều, bạn có thể chỉ cần trừ số đã biết này khỏi df -ikết quả hiện tại . Bằng cách này, bạn sẽ có thể đếm các tập tin và thư mục rất nhanh.


"Biến thể này nhanh hơn khoảng 15% ..." khiến tôi tự hỏi liệu có một loại mẹo tiện dụng nào bạn đang sử dụng để xử lý chúng không?
Brian Z

4
@BrianZ: Bạn có thể tính thời gian một lệnh bằng cách chuẩn bị lệnh theo thời gian. time find /usr/src/ -printf \\n | wc -l, bạn có thể xóa bộ nhớ cache giữa các lần chạy vớisudo sync && sudo sysctl -w vm.drop_caches=3
MattPark 17/12/13

Vì vậy, tôi đã thấy tốc độ tăng 2% phù hợp với một trong 2 tùy chọn đầu tiên mà không cần lưu vào bộ đệm. Vì vậy, đó là một cách tuyệt vời để làm điều đó. Đếm các nút chắc chắn là tốt nhất nếu môi trường của bạn được thiết lập cho điều đó. Tôi đã không xem xét nó.
MattPark 17/12/13

-printf xnghĩa là giống như -printf '\0'? Tôi không thấy nó được đề cập trong các tài liệu.
CMCDragonkai

@CMCDragonkai: Hành động -printfhoạt động tương tự như printf()chức năng trong C với sự khác biệt chính là các %chỉ thị có ý nghĩa khác nhau. Các hành động được gọi cho mỗi tập tin được tìm thấy. Điều này có nghĩa là -printf xsẽ in ký tự xcho mọi tệp được tìm thấy (hãy thử!) Và -printf '\0'sẽ in ký tự NULL (mã ASCII 0) cho mỗi tệp được tìm thấy. -printf '\0'không có ý nghĩa đặc biệt. Cả hai sẽ làm việc như nhau trong ví dụ với wc -ctrong câu trả lời này.
pabouk

3

Tôi đã viết ffcnt cho chính xác mục đích đó. Nó lấy ra phần bù vật lý của chính các thư mục bằng fiemapioctl và sau đó lập lịch trình truyền tải thư mục theo nhiều lượt liên tiếp để giảm quyền truy cập ngẫu nhiên. Việc bạn có thực sự tăng tốc so với find | wc hay không phụ thuộc vào một số yếu tố:

  • Kiểu hệ thống tệp: các hệ thống tệp như ext4 hỗ trợ fiemapioctl sẽ có lợi nhất
  • tốc độ truy cập ngẫu nhiên: HDD có lợi hơn rất nhiều so với SSD
  • bố cục thư mục: số lượng thư mục lồng nhau càng cao, tiềm năng tối ưu hóa càng nhiều

(re) gắn với relatimehoặc thậm chí nodiratimecũng có thể cải thiện tốc độ (cho tất cả các phương thức) khi các truy cập sẽ gây ra cập nhật siêu dữ liệu.


Câu cuối cùng đó là một mẹo đáng giá! Tôi nghĩ rằng liên kết đến chương trình của bạn sẽ được cải thiện nếu bạn thêm một bản tóm tắt về cách thức hoạt động của nó. Chúng tôi thích các câu trả lời hoàn chỉnh trong chính chúng, trong trường hợp có bất kỳ điều gì xấu xảy ra với tài nguyên được liên kết (tất nhiên cũng giữ liên kết).
Toby Speight

2

Trên thực tế, trên hệ thống của tôi (Arch Linux) lệnh này

   ls -A | wc -l

nhanh hơn tất cả những điều trên:

   $ time find . | wc -l
  1893

   real    0m0.027s
   user    0m0.004s
   sys     0m0.004s
   $ time find . -printf \\n  | wc -l
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time find . -printf x  | wc -c
   1893

   real    0m0.009s
   user    0m0.000s
   sys     0m0.008s
   $ time ls -A | wc -l
   1892

   real    0m0.007s
   user    0m0.000s
   sys     0m0.004s

Tôi nghĩ rằng vấn đề với ls là nó thường trả về một cái gì đó giống như /bin/ls: Argument list too longnếu bạn sử dụng Globing, nhưng một lần nữa nó có thể hoạt động đệ quy như find, vì vậy có lẽ đó là điều cần xem xét, không sử dụng find nếu không cần thiết.
MattPark

Có vẻ như đã quá muộn (nhiều năm) để bình luận về nó, nhưng ls -Achỉ liệt kê các tệp trong thư mục hiện tại trong khi findkhông có -maxdepth 1đối số sẽ thực hiện tìm kiếm đệ quy thông qua tất cả các thư mục con.
Luciano
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.