Найти количество файлов для каждого расширения в каталоге

10

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

Я перепробовал несколько вариантов, но пока не нашел работающего решения:

  • find "$folder" -type f | sed 's/.*\.//' | sort | uniq -cэто опция, но не работает, если нет расширения файла. Мне нужно знать, сколько файлов не имеют расширения.

  • Я также попытался найти цикл в массиве, а затем суммировать результаты, но в этот раз этот код выдает необъявленную ошибку переменной, но только за пределами цикла:

    declare -a arr
    arr=()
    echo ${arr[@]}
    

    Это вызывает необъявленную переменную, а также после завершения цикла поиска.

тракторист
источник

Ответы:

10
find "$path" -type f | sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' | LC_COLLATE=C sort | uniq -c

Объяснение:

  • find "$path" -type f получить рекурсивный список всех файлов в "$path"папке.
  • sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' регулярные выражения:
    • /.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/ заменить все файлы без расширения на (нет).
    • s/.*\.// получить расширение оставшихся файлов.
  • LC_COLLATE=C sort отсортировать результат, сохраняя символы сверху.
  • uniq -c посчитать количество повторных записей.
гелиограф
источник
9

Используя Python:

import os
from collections import Counter
from pprint import pprint

lst = []
for file in os.listdir('./'):
        name, ext = os.path.splitext(file)
        lst.append(ext)

pprint(Counter(lst))

Выход:

Counter({'': 7,
         '.png': 4,
         '.mp3': 3,
         '.jpg': 3,
         '.mkv': 3,
         '.py': 1,
         '.swp': 1,
         '.sh': 1})
Ravexina
источник
Вы, вероятно, можете избежать понимания списка, например, что ext = [ f.split('.')[-1] for f in os.listdir('./') ] Тэтлл сделает его на пару строк короче и, возможно, более питоническим
Сергей Колодяжный
Спасибо за предложение, я просто пытался написать это как можно яснее ...
Ravexina
1
Ясность - это добродетель :) Особенно, когда речь идет о коде и технической документации.
Сергей Колодяжный
6

Если у вас есть GNU awk, вы можете сделать что-то вроде

printf '%s\0' * | gawk 'BEGIN{RS="\0"; FS="."; OFS="\t"} 
  {a[(NF>1 ? $NF : "(none)")]++} 
  END{for(i in a) print a[i],i}
'

т.е. создать / увеличить ассоциативный массив с ключом в последнем .отделенном поле или какую-либо произвольную фиксированную строку, например, (none)если нет расширения.

mawkкажется, не разрешает разделять записи на ноль байтов - вы можете использовать mawkс разделителем новой строки по умолчанию, если вы уверены, что вам не нужно иметь дело с символами новой строки в именах файлов:

printf '%s\n' * | mawk 'BEGIN{FS="."; OFS="\t"} {a[(NF>1 ? $NF : "(none)")]++} END{for(i in a) print a[i],i}'
steeldriver
источник
5

С базовой /bin/shили даже bashс задачей может быть немного сложно, но, как вы можете видеть из других ответов, инструменты, которые могут работать с агрегированными данными, могут справиться с такой задачей особенно легко. Одним из таких инструментов будет sqliteбаза данных.

Самым простым процессом использования sqliteбазы данных будет создание .csvфайла с двумя полями: имя файла и расширение. Позже sqliteможно использовать простое совокупное заявление COUNT()с GROUP BY extдля выполнения подсчета файлов на основе расширения поля

$ { printf "file,ext\n"; find -type f -exec sh -c 'f=${1##*/};printf "%s,%s\n" "${1}" "${1##*.}"' sh {} \; ; }  > files.csv
$ sqlite3 <<EOF
> .mode csv
> .import ./files.csv files_tb
> SELECT ext,COUNT(file) FROM files_tb GROUP BY ext;
> EOF
csv,1
mp3,6
txt,1
wav,27
Сергей Колодяжный
источник
files_tbЯ думаю, что на таблицу ссылаются, но столбцы таблицы нигде не определены?
WinEunuuchs2Unix
@ WinEunuuchs2Unix Они определены в самом файле CSV. Это то, что printfделает первый . И SQLite по умолчанию будет обрабатывать первую строку файла CSV как имена столбцов.
Сергей Колодяжный
1
Очень впечатляюще! +1
WinEunuuchs2Unix
5

Использование PowerShell, если это возможно:

Get-ChildItem -File | Group-Object Extension -NoElement

или короче, используя псевдонимы:

ls -file | group -n Extension
детеныш
источник
1
Вот Это Да! Отличный первый ответ! Я даже не знал, что PowerShell существует для Linux ... +1
Fabby
2
Спасибо. Некоторое время он существовал кроссплатформенный и с открытым исходным кодом, но на SO и SU был шаблон, на который часто задавались вопросы о сценариях оболочки в Windows: «Ну, установите Cygwin и используйте bash, тогда вы можете сделать следующее ", поэтому я не решался сделать то же самое для сайтов Linux SE с инструментами, созданными в Windows. Но это была хорошая задача, которая довольно хорошо демонстрирует сильные стороны PowerShell, не привлекая старого аргумента о многословности.
Джои