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


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цикл, чтобы сделать это?

Ответы:


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[@]}с $#и"$@"


23

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

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

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

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

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


ммм ... позже я должен отфильтровать каждое найденное расширение для выполнения действия для него?
— 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

3
Не забудьте начальный каталог с find. Кроме того, это может помочь будущим читателям этих ответов, если вы дадите краткое объяснение своего решения (на случай, если они захотят изменить его для немного другого случая).
— Джефф Шаллер

Насколько хорошо это решение работает с путевыми именами, содержащими пробелы? Newlines?
— дхаг

1
findпо умолчанию используется текущий каталог, как я это использую. Я не думаю, что Бог хотел, чтобы в именах файлов были пробелы, но в этом случае это прекрасно работает. Если у вас есть переводы строк, то вы заслуживаете всего, что получаете. Я подумал об объяснении, но решил, что ответ будет слишком длинным, думаю, важна простота. 99% случаев в 1% случаев. Это, вероятно, версия 7 совместима.
— Нейк


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
— Джефф Шаллер
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.