Làm thế nào để đếm số lượng tệp trong mỗi thư mục?


104

Tôi có thể liệt kê tất cả các thư mục bằng

find ./ -type d

Tôi đã cố gắng liệt kê nội dung của từng thư mục và đếm số lượng tệp trong mỗi thư mục bằng cách sử dụng lệnh sau

find ./ -type d | xargs ls -l | wc -l

Nhưng điều này tính tổng số dòng được trả về bởi

find ./ -type d | xargs ls -l

Có cách nào để tôi có thể đếm số lượng tệp trong mỗi thư mục không?


Bạn đang tìm cách để đếm số lượng tệp trong từng thư mục con trực tiếp dưới đây ./?
Tuxdude

5
Làm thế nào đây là một câu hỏi lạc đề ?? Tôi muốn xem những ý kiến ​​đóng góp của cử tri có lý do! Nếu cái này lạc đề thì cái này thuộc về đâu? siêu người dùng? Tôi không nghĩ vậy ..
InfantPro'Aravind '

6
shell-script, batch-script thuộc phạm vi lập trình!
InfantPro'Aravind '

Tôi đã định đăng giải pháp Pythonic thì tôi nhận thấy rằng câu hỏi đã được đóng lại.
anatoly techtonik

đã bỏ phiếu để mở lại nó. Có thể có những câu trả lời khác có thể hữu ích trong nhiều tình huống (bao gồm cả lập trình kịch bản, đó là lý do tôi đạt được câu hỏi này).
lepe

Câu trả lời:


110

Giả sử bạn có GNU find, hãy để nó tìm các thư mục và để bash làm phần còn lại:

find . -type d -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done

2
Nó chỉ là một phiên bản hoàn toàn khác với phiên bản ở trên, vì vậy: (gợi ý: nó được sắp xếp theo tên và nó theo csv) cho x in find . -maxdepth 1 -type d | sort; làm y = find $x | wc -l; echo $ x, $ y; xong
pcarvalho

5
Tuyệt vời! Đưa nó thành một dòng duy nhất (vì vậy nó confortable để sử dụng trực tiếp trong vỏ):find . -type d -print0 | while read -d '' -r dir; do files=("$dir"/*); printf "%5d files in directory %s\n" "${#files[@]}" "$dir"; done
lucaferrario

13
Tôi cần lấy số lượng tất cả các tệp (đếm đệ quy) trong mỗi thư mục con. Sửa đổi này mang lại cho bạn điều đó: find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find $dir -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
OmidS

1
@Kory Điều sau sẽ làm điều đó:find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done | sort -rn -k1
OmidS

1
@OmidS Oneliner tuyệt vời, nhưng $dirphải nằm trong dấu ngoặc kép trong nhận xét đầu tiên của bạn để xử lý chính xác các tên dir có khoảng trắng. :find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
Radek Daniluk

183

Thao tác này sẽ in số lượng tệp trên mỗi thư mục cho cấp thư mục hiện tại:

du -a | cut -d/ -f2 | sort | uniq -c | sort -nr

9
Cho đến nay, giải pháp tốt nhất (và thanh lịch nhất) nếu bạn muốn liệt kê số lượng tệp trong thư mục cấp cao nhất một cách đệ quy.
itoctopus,

13
Điều này có hai vấn đề: Nó đếm một tệp trên mỗi thư mục nhiều hơn thực tế và nó đưa ra một dòng vô ích chứa kích thước của thư mục hiện tại là "1 size ". Cả hai đều có thể được sửa với du -a | sed '/.*\.\/.*\/.*/!d' | cut -d/ -f2 | sort | uniq -c. Thêm | sort -nrđể sắp xếp theo số lượng thay vì tên thư mục.
món tráng miệng

3
Tôi muốn chỉ ra rằng điều này cũng hoạt động trong OSX. (Chỉ cần sao chép-dán lời khuyên Linux vào một trình bao OSX thường không hoạt động.)
Pistos

2
nó tìm nạp kích thước không cần thiết bởi du -a. Cách tốt hơn là sử dụng lệnh find. nhưng ý tưởng chính hoàn toàn giống nhau :)
Znik

5
tìm thấy . -loại f | cắt -d / -f2 | sắp xếp | uniq -c | loại -nr # sửa chữa các vấn đề được đề cập bởi món tráng miệng
jcomeau_ictx

28
find . -type f | cut -d/ -f2 | sort | uniq -c
  • find. -type f để tìm tất cả các mục của loại tệp
  • cut -d/ -f2 để cắt ra thư mục cụ thể của họ
  • sort để sắp xếp danh sách các tên thư mục
  • uniq -c để trả về số lần mỗi tên thư mục đã được đếm

8
Điều này tốt hơn rất nhiều so với câu trả lời được chấp nhận, vì bạn nhận được một bản tóm tắt về các thư mục cấp cao nhất!
Jason Floyd

3
Đây phải là câu trả lời được chấp nhận. Đơn giản và dễ hiểu.
xssChauhan

1
Câu trả lời tốt nhất nên được chấp nhận là câu trả lời này.
loretoparisi

1
Đơn giản, thanh lịch và hoàn hảo cho nhu cầu của tôi.
RichR

Hoàn hảo. Và có thể được mở rộng để đếm qua các thư mục con bằng cách thay thế các bộ chỉ định trường bằng một danh sách các bộ chỉ định trường. Ví dụfind . -type f | cut -d/ -f2,3 | sort | uniq -c
algal

15

Bạn có thể sắp xếp để tìm tất cả các tệp, xóa tên tệp, để lại cho bạn một dòng chỉ chứa tên thư mục cho mỗi tệp, sau đó đếm số lần mỗi thư mục xuất hiện:

find . -type f |
sed 's%/[^/]*$%%' |
sort |
uniq -c

Bí quyết duy nhất trong trường hợp này là nếu bạn có bất kỳ tên tệp hoặc tên thư mục nào chứa ký tự dòng mới, điều này khá khó xảy ra. Nếu bạn thực sự phải lo lắng về dòng mới trong tên tệp hoặc tên thư mục, tôi khuyên bạn nên tìm chúng và sửa chúng để chúng không chứa dòng mới (và lặng lẽ thuyết phục bên có lỗi về lỗi của cách làm của họ).


Nếu bạn quan tâm đến số lượng tệp trong mỗi thư mục con của thư mục hiện tại, đếm bất kỳ tệp nào trong bất kỳ thư mục con nào cùng với các tệp trong thư mục con ngay lập tức, thì tôi sẽ điều chỉnh sedlệnh để chỉ in thư mục cấp cao nhất:

find . -type f |
sed -e 's%^\(\./[^/]*/\).*$%\1%' -e 's%^\.\/[^/]*$%./%' |
sort |
uniq -c

Mẫu đầu tiên ghi lại phần bắt đầu của tên, dấu chấm, dấu gạch chéo, tên cho đến dấu gạch chéo tiếp theo và dấu gạch chéo, và thay thế dòng chỉ bằng phần đầu tiên, do đó:

./dir1/dir2/file1

được thay thế bởi

./dir1/

Thay thế thứ hai nắm bắt các tệp trực tiếp trong thư mục hiện tại; chúng không có dấu gạch chéo ở cuối và chúng được thay thế bằng ./. Việc sắp xếp và đếm sau đó chỉ hoạt động dựa trên số lượng tên.


1
Điều này không xuất ra các tên thư mục không chứa bất kỳ tệp nào. Không chắc chắn nếu điều này là bắt buộc.
Austin Phillips

Đúng, nó không. 'Việc sửa chữa nó để làm như vậy không phải là điều đặc biệt nhỏ, vì các tên thư mục trống không được đảm bảo thậm chí xuất hiện trong đầu ra của find. Một số có thể: nếu có một tệp dir1/dir2/dir3/file1, nhưng dir1/dir2chỉ chứa các thư mục con (không có tệp thuần túy), thì bạn có thể suy ra sự hiện diện của nó. Nhưng nếu dir1/dir4không có tệp, tên của nó sẽ không xuất hiện.
Jonathan Leffler

Câu trả lời rất hữu ích nếu bạn chỉ muốn xem các thư mục con của thư mục hiện tại.
xixixao 21/10/14

Chỉ cần ghé qua để nói lời cảm ơn. 3 năm sau khi nó được đăng, tôi đã tìm cách đếm các thư mục cấp 2 trên mỗi thư mục. Bài viết của bạn đã cứu tôi có khả năng nhiều giờ mày mò với sed, tìm và ai biết được những gì khác
Corvin

13

Đây là một cách để làm điều đó, nhưng có lẽ không phải là cách hiệu quả nhất.

find -type d -print0 | xargs -0 -n1 bash -c 'echo -n "$1:"; ls -1 "$1" | wc -l' --

Cung cấp đầu ra như thế này, với tên thư mục theo sau là số mục nhập trong thư mục đó. Lưu ý rằng số lượng đầu ra cũng sẽ bao gồm các mục nhập thư mục có thể không phải là thứ bạn muốn.

./c/fa/l:0
./a:4
./a/c:0
./a/a:1
./a/a/b:0

Có vẻ như rất tốn kém để chạy 3 lệnh ( bash, ls, wc) cho mỗi thư mục tìm thấy bằng find.
Jonathan Leffler

@JonathanLeffler Đồng ý, do đó dòng đầu tiên của câu trả lời của tôi. Giải pháp của bạn tốt hơn.
Austin Phillips

tuyệt, đây là thứ tôi đang tìm, tôi có thể hỏi dấu '-' ở cuối là gì không?
một lần

1
@once The - thuộc về lệnh bash sẽ được tạo bởi xargs. Từ man bash, A -- signals the end of options and disables further option processing. Trong trường hợp này, nó sẽ ngăn một tệp có tên sai được tìm thấy như một phần của kết quả tìm thấy trở thành một phần của quá trình xử lý đối số cho bash.
Austin Phillips

8

Giải pháp của những người khác đều có nhược điểm này hay nhược điểm khác.

find -type d -readable -exec sh -c 'printf "%s " "$1"; ls -1UA "$1" | wc -l' sh {} ';'

Giải trình:

  • -type d: chúng tôi quan tâm đến các thư mục.
  • -readable: Chúng tôi chỉ muốn chúng nếu có thể liệt kê các tệp trong đó. Lưu ý rằng findsẽ vẫn phát ra lỗi khi nó cố gắng tìm kiếm thêm các thư mục trong đó, nhưng điều này ngăn không -execcho gọi chúng.
  • -exec sh -c BLAH sh {} ';': cho mỗi thư mục, chạy đoạn script này, với $0set thành sh$1đặt thành tên tập tin.
  • printf "%s " "$1": in tên thư mục một cách dễ dàng và tối thiểu, theo sau chỉ là dấu cách, không phải dòng mới.
  • ls -1UA: liệt kê các tệp, mỗi tệp một dòng, theo thứ tự thư mục (để tránh làm ngưng trệ đường ống), chỉ loại trừ các thư mục đặc biệt ...
  • wc -l: đếm dòng

1
Việc sửa đổi để hiển thị số lượng tệp đầu tiên trên dòng và sắp xếp theo chúng:find -type d -readable -exec sh -c 'ls -1UA "$1" | wc -l | tr -d "\n" ; printf "\t%s\n" "$1" ' sh {} ';' | sort -n
Evgeni Sergeev

nó thực hiện shell nhiều lần, sau đó nó chậm và sử dụng nhiều tài nguyên.
Znik

6

Phiên bản sửa đổi một chút của câu trả lời của Sebastian bằng cách sử dụng findthay vì du(để loại trừ chi phí liên quan đến kích thước tệp duphải thực hiện và không bao giờ được sử dụng):

 find ./ -mindepth 2 -type f | cut -d/ -f2 | sort | uniq -c | sort -nr

-mindepth 2tham số được sử dụng để loại trừ các tệp trong thư mục hiện tại. Nếu bạn xóa nó, bạn sẽ thấy một loạt các dòng như sau:

  234 dir1
  123 dir2
    1 file1
    1 file2
    1 file3
      ...
    1 fileN

(giống như dubiến thể dựa trên cơ sở)

Nếu bạn cũng cần đếm các tệp trong thư mục hiện tại, hãy sử dụng phiên bản nâng cao này:

{ find ./ -mindepth 2 -type f | cut -d/ -f2 | sort && find ./ -maxdepth 1 -type f | cut -d/ -f1; } | uniq -c | sort -nr

Đầu ra sẽ giống như sau:

  234 dir1
  123 dir2
   42 .

5

Điều này cũng có thể được thực hiện bằng cách lặp qua ls thay vì tìm

for f in */; do echo "$f -> $(ls $f | wc -l)"; done

Giải trình:

for f in */; - vòng lặp trên tất cả các thư mục

do echo "$f -> - in ra từng tên thư mục

$(ls $f | wc -l) - gọi ls cho thư mục này và đếm dòng


1
Điều này không hoạt động bình thường nếu tên thư mục chứa khoảng trắng.
Xylol

Hãy thửfor f ./* ; do echo $f $(ls "$f" | wc -l); done
4ndt3s

3

Điều này sẽ trả về tên thư mục theo sau là số lượng tệp trong thư mục.

findfiles() {
    echo "$1" $(find "$1" -maxdepth 1 -type f | wc -l)
}

export -f findfiles

find ./ -type d -exec bash -c 'findfiles "$0"' {} \;

Ví dụ đầu ra:

./ 6
./foo 1
./foo/bar 2
./foo/bar/bazzz 0
./foo/bar/baz 4
./src 4

export -fbắt buộc vì -execđối số của findkhông cho phép thực thi một hàm bash trừ khi bạn gọi hàm bash một cách rõ ràng và bạn cần xuất hàm được xác định trong phạm vi hiện tại sang shell mới một cách rõ ràng.


Điều này có vẻ quá phức tạp. Đối với tôi, nó cũng giống như nó cung cấp số lượng tích lũy cho một hệ thống phân cấp thư mục chẳng hạn như ./dir1/dir2/dir3(đếm tất cả các tệp trong dir1và thư mục con của nó cùng nhau, thay vì đếm các tệp trong dir1/dir2/dir3riêng biệt với những tệp trong dir1/dir2và cả hai tách biệt với những tệp trong /dir1).
Jonathan Leffler

Tôi hiểu đó là điều mà tác giả muốn. Nếu không phải như vậy, thì tôi đồng ý rằng câu trả lời không liên quan đến câu hỏi.
Tuxdude

1
@JonathanLeffler - Được rồi, đọc lại câu hỏi một lần nữa, tôi nhận ra bạn đúng - đã sửa đổi câu trả lời cho phù hợp.
Tuxdude

2

Tôi kết hợp câu trả lời @glenn jackman của và @ trả lời pcarvalho của (trong danh sách bình luận, có cái gì đó sai với câu trả lời pcarvalho vì thêm chức năng điều khiển phong cách của nhân vật ' ' '(backtick)).

Tập lệnh của tôi có thể chấp nhận đường dẫn như một tài liệu bổ sung và sắp xếp danh sách thư mục ls -l, cũng có thể xử lý vấn đề "khoảng trống trong tên tệp" .

#!/bin/bash
OLD_IFS="$IFS"
IFS=$'\n'
for dir in $(find $1 -maxdepth 1 -type d | sort); 
do
    files=("$dir"/*)
    printf "%5d,%s\n" "${#files[@]}" "$dir"
done
FS="$OLD_IFS"

Câu trả lời đầu tiên của tôi trong stackoverflow và tôi hy vọng nó có thể giúp ích cho ai đó ^ _ ^


1

tìm thấy . -type f -printf '% h \ n' | sắp xếp | uniq -c

cho ví dụ:

  5 .
  4 ./aln
  5 ./aln/iq
  4 ./bs
  4 ./ft
  6 ./hot

0

Tôi đã thử với một số người khác ở đây nhưng kết thúc với các thư mục con được bao gồm trong số tệp khi tôi chỉ muốn tệp. Điều này sẽ in ./folder/path<tab>nnnvới số lượng tệp, không bao gồm các thư mục con, cho mỗi thư mục con trong thư mục hiện tại.

for d in `find . -type d -print` 
do 
  echo -e "$d\t$(find $d -maxdepth 1 -type f -print | wc -l)"
done

0

Cách dễ dàng để tìm một cách đệ quy các tệp thuộc một loại nhất định. Trong trường hợp này, các tệp .jpg cho tất cả các thư mục trong thư mục hiện tại:

find . -name *.jpg -print | wc -l


0

Một lệnh phép màu siêu nhanh, duyệt đệ quy các tệp để đếm số lượng hình ảnh trong một thư mục và sắp xếp đầu ra theo phần mở rộng hình ảnh:

find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'

Tín dụng: https://unix.stackexchange.com/a/386135/354980


0

Đây có thể là một cách khác để duyệt qua cấu trúc thư mục và cung cấp kết quả chuyên sâu.

find . -type d  | awk '{print "echo -n \""$0"  \";ls -l "$0" | grep -v total | wc -l" }' | sh 

0

Tôi đã chỉnh sửa tập lệnh để loại trừ tất cả node_modules thư mục bên trong tập lệnh được phân tích.

Điều này có thể được sử dụng để kiểm tra xem số lượng tệp của dự án có vượt quá số lượng tối đa mà trình xem tệp có thể xử lý hay không.

find . -type d ! -path "*node_modules*" -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done

Để kiểm tra các tệp tối đa mà hệ thống của bạn có thể xem:

cat /proc/sys/fs/inotify/max_user_watches

node_modules thư mục phải được thêm vào các đường dẫn loại trừ IDE / trình soạn thảo của bạn trong các hệ thống chậm và số lượng tệp khác lý tưởng không nên vượt quá mức tối đa (có thể thay đổi được).


-1

Điều này sẽ cung cấp tổng số.

for file in */; do echo "$file -> $(ls $file | wc -l)"; done | cut -d ' ' -f 3| py --ji -l 'numpy.sum(l)'

Không nó sẽ không như vậy. Nó sẽ chỉ xem xét một cấp độ của các thư mục con.
Kusalananda
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.