Подсчет файлов в каталоге по расширению

15

В целях тестирования я хотел бы подсчитать, сколько файлов изображений находится в каталоге, отделяя каждый тип файла изображения по расширению (jpg = "yes". Это потому, что позже это будет полезно для другого сценария, который будет выполнять действие на каждое расширение файла). Могу ли я использовать что-то вроде следующего только для файлов JPEG?

jpg=""
count=`ls -1 *.jpg 2>/dev/null | wc -l`
if [ $count != 0 ]
then
echo jpg files found: $count ; jpg="yes"
fi

Учитывая расширения файлов jpg, png, bmp, raw и другие, я должен использовать whileцикл, чтобы сделать это?

watchmansky
источник

Ответы:

14

Я бы предложил другой подход, избегая возможных проблем разделения слов ls

#!/bin/bash

shopt -s nullglob

for ext in jpg png gif; do 
  files=( *."$ext" )
  printf 'number of %s files: %d\n' "$ext" "${#files[@]}"

  # now we can loop over all the files having the current extension
  for f in "${files[@]}"; do
    # anything else you like with these files
    :
  done 

done

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


Более переносимо - или для оболочек, которые не предоставляют массивы явно - вы можете повторно использовать массив позиционных параметров оболочки, т.е.

set -- *."$ext"

а затем заменить ${#files[@]}и ${files[@]}с $#и"$@"

steeldriver
источник
23

Мой подход будет следующим:

  1. Список всех файлов в каталоге
  2. Распакуйте их расширение
  3. Сортировать результат
  4. Подсчитайте вхождения каждого расширения

Вроде как (последний awkвызов только для форматирования):

ls -q -U | awk -F . '{print $NF}' | sort | uniq -c | awk '{print $2,$1}'

(предполагается, что GNU lsздесь для -Uопции, чтобы пропустить сортировку как оптимизацию. Она может быть безопасно удалена без ущерба для функциональности, если не поддерживается).

groxxda
источник
ммм ... позже я должен отфильтровать каждое найденное расширение для выполнения действия для него?
watchmansky
Это зависит от того, что вы хотите сделать в конце концов. Можете ли вы дать больше информации?
Groxxda
Моя цель: скрипт, который обрабатывает каждый файл расширения (только файл изображения), изменяя размер от введенных пользовательских данных. Итак, я начинаю с того, сколько там файлов jpg, следующего png и т. Д.
watchmansky
Решение SteelDrivers может быть более подходящим, чем.
Groxxda
2
У меня были JPGи jpgфайлы, и файлы, и я хотел их рекурсивно, поэтому мое решение было написатьfind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Кристиан
11

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

$ find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'
   6 tiff
   7 bmp
  26 jpeg
  38 gif
  51 jpg
  54 png
Комплект
источник
6
find -type f | sed -e 's/.*\.//' | sort | uniq -c
Neik
источник
3
Не забудьте начальный каталог с find. Кроме того, это может помочь будущим читателям этих ответов, если вы дадите краткое объяснение своего решения (на случай, если они захотят изменить его для немного другого случая).
Джефф Шаллер
Насколько хорошо это решение работает с путевыми именами, содержащими пробелы? Newlines?
дхаг
1
findпо умолчанию используется текущий каталог, как я это использую. Я не думаю, что Бог хотел, чтобы в именах файлов были пробелы, но в этом случае это прекрасно работает. Если у вас есть переводы строк, то вы заслуживаете всего, что получаете. Я подумал об объяснении, но решил, что ответ будет слишком длинным, думаю, важна простота. 99% случаев в 1% случаев. Это, вероятно, версия 7 совместима.
Нейк
3

Может быть, это может стать короче

exts=( *.jpg *.png *.gif ); printf "There are ${#exts[@]}" extensions;
Валентин Байрами
источник
3

Все, что связано ls, может привести к неожиданным результатам со специальными символами (пробел и другие символы). Любой bashism (как массивы) не переносим. Все, что связано while read, обычно идет медленно.

С другой стороны, findон ОЧЕНЬ гибок (множество опций для фильтрации), имеет [как минимум] два синтаксиса, которые отказоустойчивы для специальных символов ... и хорошо масштабируется в больших каталогах.

В этом примере я использовал -inameсовпадение с расширением в верхнем и нижнем регистре. Я также ограничил -maxdepth 1соблюдение вашего вопроса "в текущем каталоге". Вместо подсчета количества строк, где имена файлов могут включать в себя CR / LF, -print0будет печататься байт NULL в конце каждого имени файла ... так же | tr -d -c "\000" | wc -lкак и точный подсчет файлов (NULL байт!).

extensions="jpg png gif"
for ext in $extensions; do
  c=$(find . -maxdepth 1 -iname "*.$ext" -print0 | tr -d -c "\000" | wc -c)
  if [ $c -gt 0 ]; then
    echo "Found $c  *.$ext files"

    find . -maxdepth 1 -iname "*.$ext" -print0 | xargs -0 -r -n1 DOSOMETHINGHERE
    # or #  find . -maxdepth 1 -iname "*.$ext" -exec "ls" "-l" "{}" ";"
  fi
done

PS -print0 | tr -d -c "\000" | wc -cможно заменить на -printf "\000" | wc -cили даже -printf '\n' | wc -l.

Франклин Пиат
источник
0

можно просто использовать ls для чего-то такого простого IMO

ls -l /opt/ssl/certs/*.pem | wc -l

или

count=$(ls -l /some/folder/*.jpg | wc -l)

или

ls *.{mp3,exe,mp4} 2>/dev/null | wc -l
Майк К
источник
-2

Если вы уверены в расширении, вы можете пойти с findкак

find *.jpeg | wc -l
Нитиш СП
источник
пока кто-то не создаст, touch $'foo\nbar.jpegи он будет засчитан дважды вместо одного. Или хуже, кто-то делаетmkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Джефф Шаллер