Найти каталоги, содержащие определенное количество файлов

13

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

find . -filecount +10 # any directory with more than 10 entries
find . -filecount 20 # any directory with exactly 20 entries

Но, увы, такой возможности нет.

Пол Руане
источник
попробуйте что-то вроде "ls -al | wc -l | grep"
Ванадис

Ответы:

16

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

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \;

Если вы хотите сделать то же самое для всех подкаталогов (рекурсивный поиск), используйте это вместо:

find . -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \;

Чтобы выбрать те каталоги, которые имеют ровно 10 файлов:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
  awk '$NF==10'

10 или больше:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
 awk '$NF>=10'

10 или меньше:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
 awk '$NF<=10'

Если вы хотите сохранить только имя каталога (например, если вы хотите передать его другому процессу вниз по потоку, как предложено @evilsoup), вы можете использовать это:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{}\t'; ls '{}' | wc -l" \; | 
 awk -F"\t" '$NF<=10{print $1}'
terdon
источник
1
Я думаю, что было бы полезно включить команду awk, чтобы отсечь количество файлов (то есть последний столбец с пробелами), на тот случай, если спрашивающий хочет передать вывод чему-либо еще.
Evilsoup
1
@evilsoup хорошая идея, готово.
Terdon
Поддерживать пробелы и специальные символы в именах каталогов; попробуйте find . -type d -exec bash -c 'echo -ne "{} "; ls "{}" | wc -l' \; | awk '$NF<=10'
поменять местами одинарные
3

Чтобы перечислить непосредственные подкаталоги, содержащие именно $NUM файлы.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]==num) printf "%s\n", line}'

Чтобы перечислить непосредственные подкаталоги, содержащие больше, чем $NUMфайлы.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]>num) printf "%s\n", line}'

Для того, чтобы перечислить немедленные подкаталоги , содержащие меньше , чем $NUMфайлы.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]<num) printf "%s\n", line}'

Элементы завершаются нулевым символом \0, поэтому имена файлов, содержащие символы новой строки или другие типы пробелов, будут интерпретироваться правильно. %hПечатает каждый файл dirname. awkзатем использует массив, чтобы подсчитать, сколько раз он встречает каждый каталог, распечатывая его, если выполняются условия.

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

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

Шесть
источник
2

Попробуй это:

[найти. | wc -l` -eq 10] && echo "Found"

[найти. | wc -l` -gt 10] && echo "Найдено"

[найти. | wc -l` -lt 10] && echo "Найдено"

В этих примерах вы можете проверить, содержит ли каталог CURRENT ровно 10, более 10 и менее 10 файлов / каталогов. Если вам нужно проверить несколько каталогов, просто используйте цикл.

сентябрь
источник
Ваше решение также учитывает текущий каталог ( .), вы можете изменить соответствующим образом.
тердон
Мне нравится суть этого ответа (потому что я жажду делать что-то в оболочке), но вам лучше использовать wc -l < <(printf %s\\n ./*)или printf %s\\n ./* | wc -lвнутри теста, чтобы избежать ненужного findвызова. Это также позволит избежать проблемы, отмеченной @terdon, в том числе и .в результате. Однако, это также столкнется с проблемой игнорирования файлов, начинающихся с .; Я бы решил это с помощью shopt -s dotglob(чтобы глобусы соответствовали файлам, начинающимся с ., но не с .или ..).
evilsoup
@terdon Это не важно. Это не окончательное решение, просто пример, идея. Вы можете -1 или изменить 10 на 11 в окончательной версии.
сентябрь
Я знаю, и идея хорошая, поэтому я сделал предложение.
Terdon
@ тердон. Спасибо. Может быть много разных требований, таких как: считать только файлы, но не каталоги, или ссылки, или жесткие ссылки. Подсчитывать или нет файлы в подкаталогах. Считайте скрытые файлы (например, .bashrc) ... ... так что ваше выражение может быть очень длинным. :)
сентябрь