рекурсивная статистика по типам файлов в каталоге?

65

Я сделал очистку сайта для проекта конверсии. Я хотел бы сделать некоторую статистику по типам файлов там - например, 400 .htmlфайлов, 100 .gifи т. Д. Какой простой способ сделать это? Это должно быть рекурсивно.

Редактировать: со сценарием, который выложил maxschelpzig, у меня возникли некоторые проблемы из-за архитектуры сайта, которую я добавил. Некоторые из файлов имеют имена *.php?blah=blah&foo=barс различными аргументами, поэтому он считает их уникальными. Таким образом, решение должно рассматриваться *.php*как одно и то же, так сказать.

user394
источник

Ответы:

96

Вы можете использовать findи uniqдля этого, например:

$ find . -type f | sed 's/.*\.//' | sort | uniq -c
   16 avi
   29 jpg
  136 mp3
    3 mp4

Объяснение команды

  • find рекурсивно печатает все имена файлов
  • sed удаляет из каждого имени файла префикс до расширения файла
  • uniq предполагает отсортированный ввод
    • -c делает подсчет (как гистограмма).
maxschlepzig
источник
У меня есть похожий сценарий. Просто и быстро.
Руфо Эль Магуфо
Некоторые из файлов имеют имена *.php?blah=blah&foo=barс различными аргументами, поэтому он считает их уникальными. Как я могу изменить его, чтобы искать *.php*?
user394
3
Вы можете попробовать использовать другое выражение sed, например,sed 's/^.*\(\.[a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]\).*$/\1/'
maxschlepzig
Спасибо, что нашли время, чтобы объяснить, что делает каждая часть. Так много ответов на подобные темы пропускают эту часть. / учимся ловить рыбу
MechEthan
1
@ bela83, варианты сокращения основаны на оценке короткого замыкания, поэтому моя первая версия find -name '.*' -prune -o -type f -printоценивается следующим образом: если запись в каталоге совпадает, .*то следует удалить ее, в противном случае, если это файл, распечатать его. Так как .*также совпадает ., т.е. CWD, все сокращено, то есть find даже не спускается в первый каталог. Возможно, 2-летние версии findвели себя по-другому - или тогда это был просто недосмотр. Во всяком случае, find -name '.*' -not -name . -prune -o -type f -printисправляет это.
maxschlepzig
6

С зш:

print -rl -- **/?*.*(D.:e) | uniq -c |sort -n

Модель **/?*.* соответствует всем файлам , которые имеют расширение, в текущем каталоге и его подкаталогах рекурсивно. Спецификатор glob D позволяет zshобходить даже скрытые каталоги и рассматривать скрытые файлы, .выбирая только обычные файлы. Модификатор История сохраняет только расширение файла. print -rlпечатает по одному совпадению на строку. uniq -cсчитает последовательные идентичные элементы (результат глобуса уже отсортирован). Последний вызов sortсортирует расширения по количеству использования.

Жиль "ТАК - перестань быть злым"
источник
5

Этот однострочник кажется довольно надежным методом:

find . -type f -printf '%f\n' | sed -r -n 's/.+(\..*)$/\1/p' | sort | uniq -c

В find . -type f -printf '%f\n'печатает BASENAME каждого обычного файла в дереве, без каталогов. Это избавляет от необходимости беспокоиться о каталогах, которые могут быть .в них в вашем sedрегулярном выражении.

sed -r -n 's/.+(\..*)$/\1/p'Заменяет входящее имя файла только с его расширением. Например, .somefile.extстановится .ext. Обратите внимание на инициал .+в регулярном выражении; это приводит к тому, что для любого соответствия требуется хотя бы один символ перед расширением .. Это предотвращает .gitignoreобращение с такими именами файлов , как отсутствие имени и расширение «.gitignore», что, вероятно, вам и нужно. Если нет, то замените .+с .*.

Остальная часть строки от принятого ответа.

Изменить : Если вы хотите хорошо отсортированную гистограмму в формате диаграммы Парето , просто добавьте другую sortв конец:

find . -type f -printf '%f\n' | sed -r -n 's/.+(\..*)$/\1/p' | sort | uniq -c | sort -bn

Пример вывода из встроенного дерева исходных текстов Linux:

    1 .1992-1997
    1 .1994-2004
    1 .1995-2002
    1 .1996-2002
    1 .ac
    1 .act2000
    1 .AddingFirmware
    1 .AdvancedTopics
    [...]
 1445 .S
 2826 .o
 2919 .cmd
 3531 .txt
19290 .h
23480 .c
Гари Р. Ван Сикл
источник
1

Я поместил bash-скрипт в мою ~/binпапку exhistс таким содержимым:

#!/bin/bash

for d in */ ; do
        echo $d
        find $d -type f | sed -r 's/.*\/([^\/]+)/\1/' | sed 's/^[^\.]*$//' | sed -r 's/.*(\.[^\.]+)$/\1/' | sort | uniq -c | sort -nr
#       files only      | keep filename only          | no ext -> '' ext   | keep part after . (i.e. ext) | count          | sort by count desc
done

В каком бы каталоге я ни находился, я просто набираю 'exh', вкладка автоматически завершает его, и я вижу что-то вроде этого:

$ exhist
src/
      7 .java
      1 .txt
target/
     42 .html
     10 .class
      4 .jar
      3 .lst
      2 
      1 .xml
      1 .txt
      1 .properties
      1 .js
      1 .css

PS Обрезка части после знака вопроса должна быть проста для выполнения другой командой sed, вероятно, после последней (я не пробовал): sed 's/\?.*//'

Жолт Катона
источник