Как посчитать количество файлов в каждом каталоге?

68

Я могу перечислить все каталоги на

find ./ -type d

Я попытался перечислить содержимое каждого каталога и подсчитать количество файлов в каждом каталоге, используя следующую команду

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

Но это суммировало общее количество строк, возвращаемых

find ./ -type d | xargs ls -l

Есть ли способ подсчитать количество файлов в каждом каталоге?

  • 0
    Вы ищете способ подсчитать количество файлов в каждом из подкаталогов непосредственно под ./ ?
  • 4
    Как это не по теме? Я хотел бы видеть комментарии близких избирателей с разумом! Если это не по теме, то к чему это относится? супер пользователь? Я так не думаю ..
Показать ещё 4 комментария
Теги:

16 ответов

80
Лучший ответ

Предполагая, что у вас есть поиск GNU, пусть он найдет каталоги и пусть bash сделает все остальное:

find . -type d -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done
  • 1
    Это просто немного отличная версия от вышеупомянутой, поэтому: (подсказка: она отсортирована по имени и в csv) для x в find . -maxdepth 1 -type d | sort ; сделать у = find $x | wc -l ; эхо $ x, $ y; сделанный
  • 2
    Это не будет работать, если любое имя файла имеет пробелы.
Показать ещё 7 комментариев
101

Это печатает количество файлов в каталоге для текущего уровня каталогов:

du -a | cut -d/ -f2 | sort | uniq -c | sort -nr
  • 5
    Безусловно, лучшее (и самое элегантное) решение, если вы хотите рекурсивно перечислить количество файлов в каталогах верхнего уровня.
  • 6
    Это имеет две проблемы: он считает один файл на каталог больше, чем есть на самом деле, и дает бесполезную строку, содержащую размер текущего каталога как «1 размер ». И то, и другое можно исправить с помощью du -a | sed '/.*\.\/.*\/.*/!d' | cut -d/ -f2 | sort | uniq -c . Добавить | sort -nr для сортировки по количеству, а не по имени каталога.
Показать ещё 3 комментария
12

Вы можете найти все файлы, удалить имена файлов, оставив строку, содержащую только имя каталога для каждого файла, и затем подсчитать количество раз, когда появляется каждый каталог:

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

Единственное, что у вас есть, это если у вас есть имена файлов или имена каталогов, содержащие символ новой строки, что маловероятно. Если вам действительно нужно беспокоиться о новых символах в именах файлов или именах каталогов, я предлагаю вам их найти и исправить, чтобы они не содержали символы новой строки (и спокойно убеждали виновную сторону в ошибках их способов).


Если вас интересует количество файлов в каждом подкаталоге текущего каталога, считая любые файлы в любых подкаталогах вместе с файлами в непосредственной подкаталоге, я бы адаптировал sed для печати только каталога верхнего уровня:

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

Первый паттерн фиксирует начало имени, точки, косой черты, имени до следующей косой черты и косой черты и заменяет линию только первой частью, поэтому:

./dir1/dir2/file1

заменяется на

./dir1/

Вторая замена захватывает файлы непосредственно в текущем каталоге; они не имеют косой черты в конце, и они заменяются на ./. Сортировка и подсчет затем работают только по числу имен.

  • 1
    Это не выводит имена каталогов, которые не содержат файлов. Не уверен, если это требуется.
  • 0
    Правда, это не так. Это не особенно легко исправить, поскольку пустые имена каталогов не гарантируются даже при выводе команды find . Некоторые могут: если есть файл dir1/dir2/dir3/file1 , но dir1/dir2 содержит только подкаталоги (без простых файлов), то вы можете определить его наличие. Но если у dir1/dir4 нет файлов, его имя просто не появляется.
Показать ещё 2 комментария
10

Вот один из способов сделать это, но, вероятно, не самый эффективный.

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

Выдает такой вывод, с именем каталога, за которым следует количество записей в этом каталоге. Обратите внимание, что количество выходных данных также будет содержать записи каталога, которые могут быть не такими, какие вы хотите.

./c/fa/l:0
./a:4
./a/c:0
./a/a:1
./a/a/b:0
  • 0
    Кажется, очень дорого запускать 3 команды ( bash , ls , wc ) для каждого каталога, найденного командой find .
  • 0
    @JonathanLeffler Согласен, отсюда первая строка моего ответа. Ваше решение лучше.
Показать ещё 3 комментария
6

У любого другого решения есть один недостаток.

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

Пояснение:

  • -type d: нас интересуют каталоги.
  • -readable: нам нужны только их, если можно перечислить файлы в них. Обратите внимание, что find будет по-прежнему выдавать ошибку при попытке поиска в них большего количества каталогов, но это предотвращает вызов для них -exec.
  • -exec sh -c BLAH sh {} ';': для каждого каталога запустите этот script фрагмент, с $0 установите для sh и $1 значение для имени файла.
  • printf "%s " "$1": портативно и минимально печатать имя каталога, за которым следует только пробел, а не новая строка.
  • ls -1UA: перечислите файлы, по одному в каждой строке, в порядке каталога (во избежание остановки соединения), исключая только специальные каталоги . и ..
  • wc -l: подсчитайте строки
  • 1
    Модификация для отображения количества файлов в начале строки и сортировки по ним: find -type d -readable -exec sh -c 'ls -1UA "$1" | wc -l | tr -d "\n" ; printf "\t%s\n" "$1" ' sh {} ';' | sort -n
  • 0
    он выполняет оболочку много раз, затем работает медленно и активно использует ресурсы.
Показать ещё 1 комментарий
4

Это также можно сделать с помощью looping over ls вместо find

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

Пояснение:

for f in */; - цикл по всем каталогам

do echo "$f -> - распечатать каждое имя каталога

$(ls $f | wc -l) - вызов ls для этого каталога и подсчет строк

  • 0
    Это не работает должным образом, если имена каталогов содержат пробелы.
2

Слегка измененная версия ответа Себастьяна с использованием find вместо du (чтобы исключить накладные расходы, связанные с размером файла, которые du должен выполнять и которые никогда не используются):

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

-mindepth 2 используется для исключения файлов в текущем каталоге. Если вы удалите его, вы увидите несколько строк, как показано ниже:

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

(очень похоже на вариант du -based)

Если вам нужно посчитать файлы в текущем каталоге, используйте эту расширенную версию:

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

Вывод будет выглядеть следующим образом:

  234 dir1
  123 dir2
   42 .
1

найти. -type f -printf '% h\n' | сортировать | uniq -c

дает, например:

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

Я живу здесь, для будущего напоминания

ls |parallel 'echo {} && ls {}|wc -l'
1

Это должно вернуть имя каталога, за которым следует количество файлов в каталоге.

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

export -f findfiles

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

Пример вывода:

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

export -f требуется, потому что аргумент -exec find не позволяет выполнять функцию bash, если вы явно не вызываете bash, и вам нужно экспортировать функцию, определенную в текущей области, в Новая оболочка явно.

  • 0
    Это кажется чрезмерно сложным. Мне также кажется, что он дает кумулятивный подсчет для иерархии каталогов, такой как ./dir1/dir2/dir3 (подсчет всех файлов в dir1 и его подкаталогах вместе, а не подсчет файлов в dir1/dir2/dir3 отдельно от тех, что в dir1/dir2 и оба отдельно от тех, что в /dir1 ).
  • 0
    Я понял, что это то, что хотел автор. Если это не так, то я согласен, что ответ не имеет отношения к вопросу.
Показать ещё 1 комментарий
0

ncdu - это интерактивный анализатор использования диска, который может отображать количество файлов в подкаталогах. Нажмите c чтобы показать количество детей.

0
find . -type f | cut -d/ -f2 | sort | uniq -c
  • find. -type f find. -type f найти все элементы файла типа
  • cut -d / -f2 чтобы вырезать их определенную папку
  • sort их список foldernames
  • uniq -c возвращает количество раз, которое было подсчитано каждым именем
0

Простой способ рекурсивного поиска файлов заданного типа. В этом случае файлы .jpg для всех папок в текущем каталоге:

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

0

Я объединил ответ @glenn jackman и ответ @pcarvalho (в списке комментариев что-то не так с ответом pcarvalho, потому что дополнительная функция управления стилем символа ' ' '(backtick)).

Мой скрипт может принимать path в качестве дополнения и сортировать список каталогов как ls -l, а также может решить проблему "пробела в имени файла".

#!/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"

Мой первый ответ в stackoverflow, и я надеюсь, что он поможет вам ^ _ ^

0

Это даст общий счет.

for file in */; do echo "$file -> $(ls $file | wc -l)"; done | cut -d ' ' -f 3| py --ji -l 'numpy.sum(l)'
  • 0
    Нет, не будет. Будет рассмотрен только один уровень подкаталогов.
  • 0
    Да @ Kusalananda, это работает только для одного уровня.
0

Я пробовал с некоторыми из других здесь, но в итоге оказалось, что вложенные папки включены в число файлов, когда мне нужны файлы. Это печатает ./folder/path<tab>nnn с количеством файлов, не включая подпапки, для каждой подпапки в текущей папке.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню