Tìm tổng kích thước của các tệp nhất định trong một nhánh thư mục


140

Giả sử có một thư mục lưu trữ hình ảnh, giả sử, ./photos/john_doetrong đó có nhiều thư mục con, trong đó có nhiều tệp nhất định (giả sử *.jpg). Làm cách nào tôi có thể tính kích thước tóm tắt của các tệp bên dưới john_doenhánh?

Tôi đã thử du -hs ./photos/john_doe/*/*.jpg, nhưng điều này chỉ hiển thị các tập tin cá nhân. Ngoài ra, điều này chỉ theo dõi cấp độ tổ đầu tiên của john_doethư mục, như john_doe/june/, nhưng bỏ qua john_doe/june/outrageous/.

Vì vậy, làm thế nào tôi có thể đi qua toàn bộ chi nhánh, tóm tắt kích thước của các tệp nhất định?

Câu trả lời:


183
find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

Nếu cần nhiều hơn một yêu ducầu vì danh sách tệp rất dài, nhiều tổng sẽ được báo cáo và cần được tổng hợp.


7
tìm tập tin -iname '* -exec du -cb {} + | tổng số grep $ | cắt -f1 | dán -sd + - | bc # tổng kích thước byte
Michal izmazia

3
Nếu hệ thống của bạn hoạt động theo ngôn ngữ khác thì bạn cần thay đổi tổng $ sang từ khác như razem $ bằng tiếng Ba Lan.
Zbyszek

1
Bạn có thể thêm LC_ALL=POSIXtiền tố để luôn grep cho tổng số như thế này:LC_ALL=POSIX find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$
Sven

2
Nếu bạn không sử dụng -name, sau đó thay đổi grep thành grep -P "\ttotal$"nếu không nó cũng sẽ ghi lại tất cả các tệp kết thúc bằng "tổng".
thdoan

3
@ MichalČizmazia một số shell (ví dụ: Git Bash cho Windows) không đi kèm bc, vì vậy đây là một giải pháp di động hơn:find -name '*.jpg' -type f -exec du -bc {} + | grep total$ | cut -f1 | awk '{ total += $1 }; END { print total }'
thdoan

50
du -ch public_html/images/*.jpg | grep total
20M total

cung cấp cho tôi tổng số sử dụng các .jpgtập tin của tôi trong thư mục này.

Để đối phó với nhiều thư mục, có lẽ bạn phải kết hợp điều này với một số findcách.

Bạn có thể thấy các ví dụ về lệnh du hữu ích (nó cũng bao gồm find)


2
Điều này không đi qua các thư mục cơ bản?
mbaitoff

Cách này dễ gõ hơn giải pháp được chấp nhận, nhưng chỉ đúng một nửa, nó sẽ không bao gồm hình ảnh trong các thư mục con. Tốt để biết nếu tất cả các tập tin trong một thư mục.
gbmhunter

@gbmhunter Tôi nghĩ rằng nếu bạn thêm tham số -R vào -ch, bạn cũng sẽ nhận được các thư mục con khi nó đi qua đệ quy cây thư mục. Tôi hiện không có máy tính để dùng thử mặc dù để xác nhận.
Levon

1
Tôi không thấy -Rtùy chọn tại man7.org/linux/man-pages/man1/du.1.html . Và tôi không nghĩ rằng một tùy chọn đệ quy sẽ giúp ích trong trường hợp này bởi vì shell đang thực hiện việc mở rộng toàn cầu trước khi chuyển các đối số sang du.
gbmhunter

22

Chủ yếu, bạn cần hai điều:

  • các -ctùy chọn để du, nói với nó để tạo ra một tổng lớn;
  • hoặc **( hướng dẫn kích hoạt ) hoặc find( ví dụ ) hoặc chuyển qua thư mục con.
du -ch -- **/*.jpg | tail -n 1

trả lời rất tốt. Đơn giản hơn việc sử dụng find (miễn là * hoặc ** khớp với cấu trúc thư mục)
Andre de Miranda

Nó cũng có thể xử lý danh sách các tệp rất dài trong khi sử dụng findcó thể trả về kết quả sai.
Eric Fournie

bash brace mở rộng cho phép đo nhiều bộ ký tự đại diện. du -ch -- ./{dir1,dir2}/*.jpghoặcdu -ch -- ./{prefix1*,prefix2*}.jpg
J.Money

@EricFournie Tuy nhiên tôi gặp Argument list too longlỗi khi xử lý khoảng 300k tệp văn bản.
xtluo

Số lượng đối số tối đa cho một lệnh (trong trường hợp này, tên tệp được trả về khi mở rộng ký tự đại diện) có thể được kiểm tra bằng getconf ARG_MAX. Nếu bạn có nhiều hơn, bạn sẽ cần xử lý từng tệp một hoặc từng đợt với một vòng lặp for.
Eric Fournie

17

Câu trả lời cuối cùng là:

{ find <DIR> -type f -name "*.<EXT>" -printf "%s+"; echo 0; } | bc

và thậm chí phiên bản nhanh hơn, không bị giới hạn bởi RAM, nhưng điều đó yêu cầu GNU AWK có hỗ trợ bignum:

find <DIR> -type f -name "*.<EXT>" -printf "%s\n" | gawk -M '{t+=$1}END{print t}'

Phiên bản này có các tính năng sau:

  • tất cả các khả năng findđể chỉ định các tệp bạn đang tìm kiếm
  • hỗ trợ hàng triệu tập tin
    • các câu trả lời khác ở đây bị giới hạn bởi độ dài tối đa của danh sách đối số
  • chỉ sinh ra 3 quy trình đơn giản với thông lượng đường ống tối thiểu
    • nhiều câu trả lời ở đây sinh ra các quá trình C + N, trong đó C là một số hằng và N là số lượng tệp
  • không bận tâm với thao tác chuỗi
    • phiên bản này không thực hiện bất kỳ grepping, hoặc regexing
    • tốt, findcó một ký tự đại diện đơn giản phù hợp với tên tệp
  • tùy chọn định dạng tổng thành một hình dạng con người có thể đọc được (ví dụ. 5.5K, 176.7M...)
    • để làm điều đó | numfmt --to=si

Tôi thích sự đơn giản của câu trả lời này, mặc dù nó chỉ hiệu quả với tôi khi tôi giới thiệu không gian sau khi mở nẹp và trước khi kết thúc. Tôi tự hỏi liệu nó có thực sự hỗ trợ số lượng tệp 'infiinte' không :)
andyb

1
@andyb cảm ơn bạn đã phản hồi, không gian xung quanh niềng răng thực sự cần thiết trong BASH, tôi đang sử dụng ZSH nên tôi không nhận thấy điều đó. Và số lượng tệp bị giới hạn bởi RAM có sẵn trên hệ thống của bạn khi mức sử dụng bộ nhớ của bc tăng chậm khi số lượng chảy vào.
Jan Chren - kiểm tra lại

8

Các câu trả lời được đưa ra cho đến bây giờ không tính đến việc danh sách tệp được truyền từ find sang du có thể quá dài đến mức find sẽ tự động chia danh sách thành các đoạn, dẫn đến nhiều lần xuất hiện total.

Bạn có thể grep total(miền địa phương!) Và tổng hợp thủ công hoặc sử dụng một lệnh khác. AFAIK chỉ có hai cách để có được tổng cộng (tính bằng kilobyte) của tất cả các tệp được tìm thấy:
find . -type f -iname '*.jpg' -print0 | xargs -r0 du -a| awk '{sum+=$1} END {print sum}'

Giải thích
find . -type f -iname '*.jpg' -print0: Tìm tất cả các tệp có phần mở rộng jpg bất kể trường hợp nào (ví dụ * .jpg, * .JPG, * .Jpg ...) và xuất chúng (kết thúc null).
xargs -r0 du -a: -r: Xargs sẽ gọi lệnh ngay cả khi không có đối số nào được truyền, điều này -r ngăn cản. -0 có nghĩa là chuỗi kết thúc null (không kết thúc dòng mới).
awk '{sum+=$1} END {print sum}': Tổng hợp kích thước tập tin đầu ra bằng lệnh trước

Và để tham khảo, cách khác sẽ là
find . -type f -iname '*.jpg' -print0 | du -c --files0-from=-


Gợi ý bổ sung: Trên ổ cứng của tôi có 23,28 tệp (22323 là hình ảnh), phương thức đầu tiên chạy 1 giây trong khi phương thức thứ hai chạy 3,8 giây.
Ngày

Lưu ý rằng cả hai đều giả định một hệ thống GNU. Cái đầu tiên giả sử tên tệp không chứa ký tự dòng mới.
Stéphane Chazelas

Tôi cá là du --file0-frommất nhiều thời gian hơn vì bạn đã chạy nó trước (hiệu ứng bộ đệm).
Stéphane Chazelas

Với xargs, một số du -acó thể được chạy, vì vậy bạn có thể có sự khác biệt nếu có liên kết cứng.
Stéphane Chazelas

3

Nếu danh sách các tệp quá lớn mà nó không thể được chuyển đến một lệnh gọi duy nhất du -c, trên hệ thống GNU, bạn có thể thực hiện:

find . -iname '*.jpg' -type f -printf '%b\t%D:%i\n' |
  sort -u | cut -f1 | paste -sd+ - | bc

(kích thước được thể hiện bằng số khối 512 byte). Giống như dunó cố gắng đếm các liên kết cứng chỉ một lần. Nếu bạn không quan tâm đến các liên kết cứng, bạn có thể đơn giản hóa nó thành:

(printf 0; find . -iname '*.jpg' -type f -printf +%b) | bc

Nếu bạn muốn kích thước thay vì sử dụng đĩa, thay thế %bbằng %s. Kích thước sau đó sẽ được thể hiện bằng byte.


-bash: bc: command not foundCentos - Linux 2.6.32-431.el6.x86_64
yeya

@yeya, có vẻ như việc triển khai CentOS của bạn bị hỏng. bclà một lệnh POSIX không tùy chọn.
Stéphane Chazelas

1

Các giải pháp được đề cập cho đến nay là không hiệu quả (thực hiện rất tốn kém) và yêu cầu công việc thủ công bổ sung để tổng hợp nếu danh sách tệp dài hoặc chúng không hoạt động trên Mac OS X. Giải pháp sau rất nhanh, nên hoạt động trên mọi hệ thống và mang lại tổng số câu trả lời tính bằng GB (xóa a / 1024 nếu bạn muốn xem tổng số tính bằng MB): find . -iname "*.jpg" -ls |perl -lane '$t += $F[6]; print $t/1024/1024/1024 . " GB"'


Không -inamephải -lslà tiêu chuẩn / di động, vì vậy nó sẽ không hoạt động trên bất kỳ hệ thống nào. Nó cũng sẽ không hoạt động đúng nếu có tên tệp hoặc mục tiêu liên kết tượng trưng có chứa các ký tự dòng mới.
Stéphane Chazelas

Cũng lưu ý rằng nó cung cấp tổng kích thước tệp, không sử dụng đĩa của họ. Đối với các liên kết tượng trưng, ​​nó cung cấp kích thước của các liên kết tượng trưng, ​​không phải các tệp mà chúng trỏ đến.
Stéphane Chazelas

1

Cải thiện câu trả lời tuyệt vời của SHW để làm cho nó hoạt động với bất kỳ ngôn ngữ nào, như Zbyszek đã chỉ ra trong nhận xét của mình:

LC_ALL=C find ./photos/john_doe -type f -name '*.jpg' -exec du -ch {} + | grep total$

1

du tự nhiên đi qua hệ thống phân cấp thư mục và awk có thể thực hiện quá trình lọc để một cái gì đó như thế này có thể là đủ:

du -ak | awk 'BEGIN {sum=0} /\.jpg$/ {sum+=$1} END {print sum}'

Điều này hoạt động mà không có GNU.


1
Điều này đắt hơn vì nó đòi hỏi một statcuộc gọi cho các tệp không tương ứng với mẫu tìm kiếm.
Luật29

Chỉ có giải pháp này hoạt động trên máy mac của tôi.
Matthias M
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.