Подсчитать общее количество файлов в определенном каталоге с определенным расширением

32

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

Я получаю следующую команду:

ls -F |grep -v / | wc -l

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

Есть ли какая-нибудь команда Ubuntu для этого?

Пракаш В Холкар
источник
2
Простой, правильный, прямой ответ - @ louis-matthijssen. ls -1обработка символов новой строки делает, в этом случае, разумным анализировать lsвывод. Помеченный является неправильным для использования флага -R.
Rmano

Ответы:

19

Здесь вы можете сделать это

ls -lR /path/to/dir/*.jpg | wc -l

Это дает вам счет

sk1712
источник
5
Почему то -R? Зачем делать полный, statкогда вам просто нужно имя файла? Почему нет ls -1 *.jpg| wc -l? (хорошо, не работает, если у вас есть имена файлов с символами новой строки. В этом случае вы это заслужили ;-) ...)
Rmano
2
... и вопрос был "подсчет количества файлов в каталоге". Более того, это будет рекурсивно перечислять все содержимое подкаталогов, имена которых заканчиваются на .jpg , а не файлы в подкаталогах, оканчивающихся на .jpg. Вы когда-нибудь проверяли это?
Rmano
1
Вопрос говорит «файлы в определенном каталоге», что подразумевает, что рекурсия подкаталога не нужна.
Дэвид Ричерби
1
Это также дает сбой, если в каталоге слишком много файлов (потому что *.jpgон расширяется оболочкой, а не с помощью ls) и если есть файлы, имена которых начинаются с дефиса.
Дэвид Ричерби
2
@DavidRicherby Это пропускает имена, которые начинаются с .. Но на самом деле все работает нормально с дефисами в именах, кроме случаев, когда /path/to/dirпустая строка или относительный путь начинаются с дефиса. Но я был неправ, прежде чем сказать, lsзаменяет символы с ?. Это происходит, когда stdout является терминалом, но здесь вывод является каналом, поэтому lsотправляет все символы из имен файлов в wc. Это делает этот ответ неправильным без флага -qили, -bчтобы изменить это поведение , потому что имена файлов могут содержать символы новой строки. Ответ l0b0 свободен от этих проблем.
Элия ​​Каган
42

К сожалению, эту сложную проблему трудно решить способом, который поддерживает все имена файлов и является переносимым. Это безопасно (оно обрабатывает скрытые файлы, пути, содержащие пробелы, тире и даже переводы строк) и POSIX-совместимо :

find /path/to/directory -mindepth 1 -type f -name "*.mp4" -printf x | wc -c

Если вы не хотите, чтобы он был рекурсивным, просто добавьте -maxdepth 1.

Вы не должны анализировать lsвывод.

Тест:

$ cd -- "$(mktemp -d)"
$ touch -- -foo.mp4 .bar.mp4 .bat.mp4 'baz.mp4
> ban.mp4'
$ find . -mindepth 1 -type f -name "*.mp4" -exec printf x \; | wc -c
4

Сравните с принятым ответом :

$ ls -lR ./*.mp4 | wc -l
3

Или другие предложения:

$ find . -name "*.mp4" | wc -l
5
$ ls -1 *.mp4 | wc -l
ls: invalid option -- '.'
Try 'ls --help' for more information.
0
$ find . -name "*.mp4" | wc -c # Answer fixed at a later time
51
$ find . -name "*.mp4" | wc -l
5
$ find . | grep -i ".mp4$" | wc -l
5
$ ls . | grep ".mp4$" | wc -l
3
l0b0
источник
2
Хотя этот ответ является правильным и надежным, вы можете использовать -printf xвместо -exec printf x \;. То есть: find /path/to/directory -mindepth 1 -type f -name "*.mp4" -printf x | wc -c нет необходимости -execво внешней printfкоманде, которая, если есть много файлов, будет очень медленной , потому что findона должна форкнуть (2) свою копию и затем выполнить execve (2) /usr/bin/printf . При этом -exec printf x \;это должно быть сделано один раз для каждого файла .
Элия ​​Каган
-printfне поддерживается в POSIXfind , поэтому я не использовал его.
10
1
Ни один не -mindepthи -maxdepth, которые вы использовали.
Элия ​​Каган
Хорошая мысль, я не понял этого!
10
BSD findсодержит -mindepthи -maxdepthне содержит, -printfпоэтому я ценю включение обоих.
Джозеф
11

Этот находит, сортирует и перечисляет все файлы по расширению в следующем порядке:

find . -type f | sed 's/.*\.//' | sort | uniq -c
squozen
источник
Превосходно! Я просто добавил бы | sort -rnв конце и, возможно, -mindepth 1просто текущий каталог.
Пабло А
И, возможно, труба, чтобы head -nполучить верх п.
Раман
отличный ответ, большое спасибо
Деннис Голомазов
5

Я думаю, что это очень просто, как следующие команды.

$ find . -name "*.mp4" | wc -l
8

или

$ find . | grep -i ".mp4$" | wc -l
8

Я думаю, что вышеупомянутые команды вычисляют количество имен файлов и каталогов *.mp4

поэтому я предлагаю вам использовать -type fопцию в качестве findпараметра следующим образом.

$ find . -name "*.mp4" -type f | wc -l
8

Кроме того, ls -lRможет использоваться какfind .

xiaodongjie
источник
2

Вы могли бы использовать ls -1 *.mp4 | wc -l.

Это выведет список всех файлов, заканчивающихся на .mp4, напечатав каждый файл в новой строке ( ls -1 *.mp4), wcпередаст вывод, в который будет подсчитывать количество новых строк, используя -lфлаг.

Луи Матейссен
источник
Не уверен, почему это было отклонено, это работает
Пантера
Поскольку *.mp4она расширяется оболочкой, lsэтого не произойдет, если .mp4в каталоге так много файлов, что их список не может быть передан в lsкачестве аргументов.
Дэвид Ричерби
@Rmana Протестируйте его в каталоге, содержащем файл с именем--.mp4
David Richerby
@DavidRicherby да, вы правы. --решит второй случай; первый вызовет сообщение об ошибке (вам нужно много файлов!) и еще один приятный вопрос здесь. Угловые чехлы, но стоит заметить, да.
Rmano
1
@Rmano Без добавления -qили -b, это не допускает переводы строк в именах файлов. Если вы запускаете ls -1 *.mp4из своего терминала без канала, видите , lsчто его стандартный вывод является терминалом и принимает, -qкак подразумевается, печать ?s. Но это поведение исчезает, когда вывод передается по конвейеру. ls -1 *.mp4 | wc -lПересчет, если есть новые строки. ls -1 *.mp4 | catпоказывает, что wc"видит". (Точно так же -1подразумевается, когда stdout не является терминалом, поэтому это необязательно.) ls -1q -- *.mp4 | wc -lПочти работает, но не с нулевыми файлами .mp4.
Элия ​​Каган
0

Это должно дать вам список файлов с .mp4

ls /path/to/directory | grep ".mp4$"

В сочетании с wc -lдаст вам рассчитывать

ls /path/to/directory | grep ".mp4$" | wc -l

если вы хотите, чтобы поиск включал подкаталоги

ls -lR /path/to/directory | grep ".mp4$" | wc -l
Back.Slash
источник
не дает счет
Пантера
дал его мне при использовании сwc -l
Back.Slash
используйте ls без труб, чтобы grep и сократить ваш ответ. Это было отправлено по крайней мере дважды сейчас.
Пантера
@ bodhi.zazen ls /directory/*.mp4заставляет оболочку расширять глобус и выполнять что-то вроде этого. ls /directory/file1.mp4 /directory/file2.mp4 ...Это не удастся, если каталог содержит больше файлов mp4, чем может быть передано в качестве аргументов ls.
Дэвид Ричерби
@DavidRicherby - это не моя команда ls, я использую find;)
Panther
0

В bash один холодный способ использования массивов с glob:

$ files=( *.mp4  )
$ echo ${#files[@]}
30
Сергей Колодяжный
источник
0
ls | grep --count \.csv$

Замените (.csv на нужное вам расширение)

Пояснение: я думаю, что простая схема - это получить список файлов и посчитать расширение с помощью grep. \.сопоставлять .и $сопоставлять расширение в конце строки. Это работает потому, что когда вывод ls передается по конвейеру, в каждой строке отправляется одно имя файла, что можно проверить, выполнив:

ls | cat
Мохсин Раза
источник
1
Обратите внимание, что вместо grep --count, вы также можете использовать grep -c.
Мохсин Раза