Как найти все отдельные расширения файлов в иерархии папок?

На Linux-машине я хотел бы проследить иерархию папок и получить список всех отдельных расширений файлов в ней.

Каков наилучший способ добиться этого из оболочки?

18 ответов

Решение

Попробуйте это (не уверен, что это лучший способ, но он работает):

find . -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u

Это работает следующим образом:

  • Найти все файлы из текущей папки
  • Распечатывает расширение файлов, если есть
  • Составьте уникальный отсортированный список

Нет необходимости в трубе sort, awk может сделать все это:

find . -type f | awk -F. '!a[$NF]++{print $NF}'

Моя альтернатива, не требующая использования awk-менее, sed-less, Perl-менее и Python-совместимая:

find . -type f | rev | cut -d. -f1 | rev  | tr '[:upper:]' '[:lower:]' | sort | uniq --count | sort -rn

Хитрость в том, что она переворачивает линию и обрезает расширение в начале.
Он также преобразует расширения в нижний регистр.

Пример вывода:

   3689 jpg
   1036 png
    610 mp4
     90 webm
     90 mkv
     57 mov
     12 avi
     10 txt
      3 zip
      2 ogv
      1 xcf
      1 trashinfo
      1 sh
      1 m4v
      1 jpeg
      1 ini
      1 gqv
      1 gcs
      1 dv

Рекурсивная версия:

find . -type f | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort -u

Если вы хотите итоги (как, возможно, раз расширение было замечено):

find . -type f | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort | uniq -c | sort -rn

Не рекурсивный (одна папка):

for f in *.*; do printf "%s\n" "${f##*.}"; done | sort -u

Я основал это на этом сообщении на форуме, кредит должен идти туда.

Powershell:

dir -recurse | select-object extension -unique

Спасибо http://kevin-berridge.blogspot.com/2007/11/windows-powershell.html

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

find . -type f | grep -o -E '\.[^\.]+$' | sort -u

Найдите все с точкой и покажите только суффикс.

find . -type f -name "*.*" | awk -F. '{print $NF}' | sort -u

если вы знаете все суффиксы имеют 3 символа, то

find . -type f -name "*.???" | awk -F. '{print $NF}' | sort -u

или с sed показывает все суффиксы от одного до четырех символов. Измените {1,4} на диапазон символов, которые вы ожидаете в суффиксе.

find . -type f | sed -n 's/.*\.\(.\{1,4\}\)$/\1/p'| sort -u

Я попробовал кучу ответов здесь, даже самый лучший ответ. Все они не соответствовали тому, что я был конкретно после. Таким образом, помимо последних 12 часов сидения в коде регулярных выражений для нескольких программ, чтения и тестирования этих ответов, я пришел к тому, что работает ТОЧНО, как я хочу.

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort -u
  • Находит все файлы, которые могут иметь расширение.
  • Greps только расширение
  • Greps для расширений файлов от 2 до 16 символов (просто измените числа, если они не соответствуют вашим потребностям). Это помогает избежать кеширования файлов и системных файлов (системный файл предназначен для поиска в тюрьме).
  • Awk для печати расширений в нижнем регистре.
  • Сортируйте и вносите только уникальные значения. Первоначально я пытался попробовать ответить на awk, но он удвоил бы печатные элементы, которые варьировались в зависимости от регистра.

Если вам нужно количество расширений файлов, используйте приведенный ниже код

find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort | uniq -c | sort -rn

Хотя выполнение этих методов займет некоторое время и, возможно, не является лучшим способом решения проблемы, они работают.

Обновление: для длинных расширений файлов @ @_989 возникнет проблема. Это связано с оригинальным регулярным выражением "[[:alpha:]]{3,6}". Я обновил ответ, включив в него регулярное выражение "[[:alpha:]]{2,16}". Однако любой, кто использует этот код, должен знать, что эти числа - это минимальное и максимальное значения того, как долго разрешено расширение для окончательного вывода. Все, что находится за пределами этого диапазона, будет разбито на несколько строк на выходе.

Примечание: Оригинальный пост действительно читал "- Greps для расширений файлов от 3 до 6 символов (просто измените числа, если они не соответствуют вашим потребностям). Это помогает избежать кеширования файлов и системных файлов (бит системного файла предназначен для поиска в тюрьме)."

Идея: Может быть использован для поиска расширений файлов определенной длины через:

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{4,}" | awk '{print tolower($0)}' | sort -u

Где 4 - это длина расширений файла, которую нужно включить, а затем найти также любые расширения, превышающие эту длину.

В Python использование генераторов для очень больших каталогов, включая пустые расширения, и получение количества раз, когда каждое расширение отображается:

import json
import collections
import itertools
import os

root = '/home/andres'
files = itertools.chain.from_iterable((
    files for _,_,files in os.walk(root)
    ))
counter = collections.Counter(
    (os.path.splitext(file_)[1] for file_ in files)
)
print json.dumps(counter, indent=2)

Другой путь:

find . -type f -name "*.*" -printf "%f\n" | while IFS= read -r; do echo "${REPLY##*.}"; done | sort -u

Вы можете отбросить -name "*.*" но это гарантирует, что мы имеем дело только с файлами, у которых есть какое-то расширение.

В -printf является findпечатать, а не бить. -printf "%f\n" печатает только имя файла, удаляя путь (и добавляя новую строку).

Затем мы используем подстановку строк, чтобы удалить до последней точки, используя ${REPLY##*.}.

Обратите внимание, что $REPLY просто readвстроенная переменная. Мы могли бы использовать нашу собственную в форме: while IFS= read -r file, и здесь $ file будет переменной.

Так как уже есть другое решение, которое использует Perl:

Если у вас установлен Python, вы также можете сделать (из оболочки):

python -c "import os;e=set();[[e.add(os.path.splitext(f)[-1]) for f in fn]for _,_,fn in os.walk('/home')];print '\n'.join(e)"

Я не думаю, что это было упомянуто еще:

find . -type f -exec sh -c 'echo "${0##*.}"' {} \; | sort | uniq -c

В принятом ответе используется REGEX, и вы не можете создать команду псевдонима с помощью REGEX, вы должны поместить ее в сценарий оболочки, я использую Amazon Linux 2 и сделал следующее:

  1. Я поместил принятый код ответа в файл, используя:

    sudo vim find.sh

добавьте этот код:

find ./ -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u

сохраните файл, набрав: :wq!

  1. sudo vim ~/.bash_profile

  2. alias getext=". /path/to/your/find.sh"

  3. :wq!

  4. . ~/.bash_profile

Ни один из ответов до сих пор не имел дело с именами файлов с символами новой строки должным образом (за исключением ChristopheD, которые только пришли, когда я печатал это). Следующее не является однострочным, но работает и работает достаточно быстро.

import os, sys

def names(roots):
    for root in roots:
        for a, b, basenames in os.walk(root):
            for basename in basenames:
                yield basename

sufs = set(os.path.splitext(x)[1] for x in names(sys.argv[1:]))
for suf in sufs:
    if suf:
        print suf

Я думаю, что самый простой и простой способ

for f in *.*; do echo "${f##*.}"; done | sort -u

Он модифицирован по третьему пути Кристофа.

Я нашел это просто и быстро...

   # find . -type f -exec basename {} \; | awk -F"." '{print $NF}' > /tmp/outfile.txt
   # cat /tmp/outfile.txt | sort | uniq -c| sort -n > tmp/outfile_sorted.txt

Вы также можете сделать это

find . -type f -name "*.php" -exec PATHTOAPP {} +

Если вы ищете ответ, это уважение.gitignoreзатем проверьте ответ ниже.

      git ls-tree -r HEAD --name-only | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u 
Другие вопросы по тегам