2013-03-05 2 views
52

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

find ./ -type d 

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

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

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

find ./ -type d | xargs ls -l 

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

+0

Вы ищете способ подсчета количества файлов в каждом из подкаталогов непосредственно под '. /'? – Tuxdude

+4

Как это не по теме вопрос ?? Я хотел бы, чтобы комментарии близких избирателей были по причине! ** Если это не по теме, то где это относится? ** супер пользователь? Я так не думаю .. –

+4

shell-script, пакетный скрипт находятся в области программирования! –

ответ

62

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

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-тип d | sort'; do y = 'find $ x | wc -l'; echo $ x, $ y; done – peteroak

+2

Это не сработает, если какое-либо имя файла имеет пробелы. –

+3

Отличный! Поместите его в одну строку (так что он удобен для непосредственного использования в оболочке): 'find. -тип d -print0 | при чтении -d '' -r dir; do files = ("$ dir"/*); printf "% 5d файлов в каталоге% s \ n" "$ {# files [@]}" "$ dir"; done' – lucaferrario

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 не разрешает выполнение функции Баш, если не вызывать Баш явно, и вам нужно экспортировать функцию, определенную в текущая область действия для новой оболочки явно.

+0

Это кажется чрезмерно сложным. Мне также кажется, что он дает кумулятивный счет для иерархии каталогов, такой как './Dir1/dir2/dir3' (считая файлы в' dir1' и его подкаталогах вместе, вместо того, чтобы считать файлы в 'dir1/dir2/dir3' отдельно от тех, что находятся в 'dir1/dir2', и оба отдельно от них в'/dir1'). –

+0

Я понял, что этого хотел автор. Если это не так, то я согласен, что ответ не имеет отношения к вопросу. – Tuxdude

+0

@JonathanLeffler - Хорошо, снова прочитав вопрос, я понял, что вы правы - соответственно изменили ответ. – Tuxdude

10

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

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

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


Если вы заинтересованы в подсчете файлов в каждом подкаталоге текущего каталога, считая любые файлы в любых подкаталогах вместе с файлами в непосредственной подкаталоге, то я d адаптировать команду 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' не имеет файлов, имя просто не отображается. –

+0

Очень полезный ответ, если вы просто хотите увидеть подкаталоги текущего каталога. – xixixao

9

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

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 Согласен, следовательно, первая строка моего ответа. Ваше решение лучше. –

+0

круто это то, что я ищу Могу ли я спросить, что такое '-' в конце? – once

1

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

ls |parallel 'echo {} && ls {}|wc -l' 
+0

Моя оболочка раскрашивает папки. Я использую 'ls --color = never | parallel 'echo -n {} && ls {} | wc -l'' –

54

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

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

На сегодняшний день лучшее (и самое элегантное) решение, если вы хотите рекурсивно перечислить количество файлов в каталогах верхнего уровня. – itoctopus

+3

У этого есть две проблемы: он считает один файл в каталоге больше, чем есть на самом деле, и он дает бесполезную строку, содержащую размер текущего каталога, как «1 _size_». Оба могут быть установлены с помощью 'du -a | sed '/.*\.\/.*\/.*/!d' | cut -d/-f2 | сортировать | uniq -c'. Добавить '| sort -nr' сортировать по счету вместо имени каталога. – dessert

4

Решение каждого другого имеет один недостаток.

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 {} ';': для каждого каталога запустите этот фрагмент скрипта с $0, установленным на sh и $1, установленным для имени файла.
  • printf "%s " "$1": портативно и минимально печатать имя каталога, за которым следует только пробел, а не символ новой строки.
  • ls -1UA: список файлов, по одному в каждой строке, в порядке каталогов (во избежание заклинивания трубы), за исключением только специальные каталоги . и ..
  • wc -l: кол-во линий
+0

Модификация, чтобы показать, что файл подсчитывается первым в строке и сортировать по ним: 'find -type d -readable -exec sh -c 'ls -1UA" $ 1 "| wc -l | tr -d "\ n"; printf "\ t% s \ n" "$ 1" 'sh {}'; ' | sort -n' –

0

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

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

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

Это также может быть сделано со сквозными над Ls вместо поиска

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

Пояснение:

for f in */; - цикл по всем Справочники

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

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

+0

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

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 
Смежные вопросы