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

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

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


person GloryFish    schedule 03.12.2009    source источник


Ответы (17)


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

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

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

  • Найти все файлы из текущей папки
  • Печатает расширения файлов, если они есть
  • Составьте уникальный отсортированный список
person Ivan Nevostruev    schedule 03.12.2009
comment
просто для справки: если вы хотите исключить некоторые каталоги из поиска (например, .svn), используйте find . -type f -path '*/.svn*' -prune -o -print | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u источник - person Dennis Golomazov; 22.11.2012
comment
Пробелы не будут иметь никакого значения. Каждое имя файла будет в отдельной строке, поэтому разделителем списка файлов будет \ n, а не пробел. - person Ivan Nevostruev; 21.08.2013
comment
В Windows это работает лучше и намного быстрее, чем find: dir / s / b | perl -ne 'вывести $ 1, если m /\.([^^.\\\\ ]+)$/' | sort -u - person Ryan Shillington; 10.12.2013
comment
Примечание: если вы хотите сделать это псевдонимом в .bashrc, вы должны экранировать $1 как \$1. На самом деле кажется, что экранирование $1 тоже не вредит консольному использованию. - person jakub.g; 04.12.2015
comment
вариант ответа git: используйте git ls-tree -r HEAD --name-only вместо find - person jakub.g; 04.12.2015
comment
Кажется, это показывает строку после первой точки, например. theme из page_manager.theme.inc. - person user151841; 05.01.2016
comment
Вариант, это показывает список со счетчиками на расширение: find . -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort | uniq -c | sort -n - person marcovtwout; 17.05.2016
comment
В качестве недостатка он также находит такие файлы, как configs-0.1.6, у которых нет расширений, но есть точки в имени. - person mrgloom; 03.04.2019
comment
как игнорировать скрытые файлы, попадающие в список? - person Ghansham; 23.09.2019
comment
Это черная магия, люди. Работает невероятно быстро. Невероятно! - person cablop; 25.10.2020
comment
Бит perl можно сократить perl -ne 's/.+\.// && print' - person blueray; 15.07.2021

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

find . -type f | awk -F. '!a[$NF]++{print $NF}'
person SiegeX    schedule 24.08.2011
comment
Я не получаю этого для работы в качестве псевдонима, я получаю awk: синтаксическая ошибка в строке исходного кода 1, контекст: ›››! A [] ‹**************************************************************************************************************************** Мой псевдоним определяется так: alias file_ext = find. -тип f -name '.' | awk -F. '! a [$ NF] ++ {print $ NF}' - person user2602152; 01.03.2015
comment
@ user2602152 проблема в том, что вы пытаетесь заключить весь однострочный текст в кавычки для команды alias, но сама команда уже использует кавычки в команде find. Чтобы исправить это, я бы использовал синтаксис буквальной строки bash следующим образом: alias file_ext=$'find . -type f -name "*.*" | awk -F. \'!a[$NF]++{print $NF}\'' - person SiegeX; 14.03.2015
comment
это не работает, если один подкаталог имеет расширение. в его имени, и файл не имеет расширения. Пример: когда мы запускаем из maindir, он не работает для maindir/test.dir/myfile - person Nelson Teixeira; 02.04.2017
comment
@NelsonTeixeira Добавьте -printf "%f\n" в конец команды «найти» и повторно запустите тест. - person SiegeX; 03.04.2017

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

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

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

person ChristopheD    schedule 03.12.2009
comment
Здорово! также работает для моего сценария git, пытался выяснить, какой тип файлов я затронул в последней фиксации: git show --name-only --pretty="" | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort -u - person vulcan raven; 03.02.2020

Powershell:

dir -recurse | select-object extension -unique

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

person Simon R    schedule 23.04.2010
comment
OP сказал на машине Linux - person Forbesmyester; 05.08.2013
comment
на самом деле сейчас существует prowershell для Linux: github.com/Microsoft/PowerShell-DSC-for -Linux - person KIC; 16.09.2016
comment
Как написано, это также выберет каталоги, в которых есть . (например, jquery-1.3.4 будет отображаться как .4 в выводе). Измените на dir -file -recurse | select-object extension -unique, чтобы получать только расширения файлов. - person mcw; 05.03.2018
comment
@Forbesmyester: Люди с Windows (например, я) найдут этот вопрос для. Так что это полезно. - person Roel; 25.02.2020
comment
Спасибо за ответ Powershell. Вы не предполагаете, как пользователи ищут. Многие люди проголосовали за - person Mahesh; 08.04.2020

Моя альтернатива без awk, sed, без Perl, без Python, совместимая с POSIX:

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
person Ondra Žižka    schedule 23.03.2019
comment
на Mac uniq не имеет полного флага --count, но -c работает нормально - person worc; 28.01.2020
comment
Очень круто, было бы неплохо, если бы сюда не вошли файлы, у которых нет расширений. Запуск этого на основе репо приводит к уйме файлов git без расширений. - person Chris Hayes; 06.08.2020
comment
@ChrisHayes, простая помощь: find . -type f -name '*.?* .... ', не полностью протестирован, но должен работать. - person Ondra Žižka; 27.09.2020

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

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
person user224243    schedule 03.12.2009
comment
Нет необходимости в конвейере для «сортировки», awk может все это сделать: find. -тип f -name . | awk -F. '! a [$ NF] ++ {print $ NF}' - person SiegeX; 06.12.2009
comment
@SiegeX Ваш должен быть отдельным ответом. Было обнаружено, что эта команда лучше всего работает для больших папок, поскольку она печатает расширения по мере их нахождения. Но учтите, что это должно быть: -name . - person Ralf; 18.08.2011
comment
@Ralf готово, опубликован ответ здесь. Не совсем уверен, что вы имеете в виду под словом -name ".", потому что это то, что уже есть - person SiegeX; 24.08.2011
comment
Я имел в виду, что это должно быть -name *. *, Но StackOverflow удаляет символы *, что, вероятно, также произошло в вашем комментарии. - person Ralf; 24.08.2011
comment
Похоже, что это должен быть принятый ответ, awk предпочтительнее perl в качестве инструмента командной строки, и он охватывает философию unix, заключающуюся в объединении небольших совместимых программ в связные и читаемые процедуры. - person Jon z; 15.09.2015

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

find . -type f | grep -oE '\.(\w+)$' | sort -u
person gkb0986    schedule 15.07.2013
comment
+1 для переносимости, хотя регулярное выражение довольно ограничено, поскольку оно соответствует только расширениям, состоящим из одной буквы. Кажется, лучше использовать регулярное выражение из принятого ответа: $ find . -type f | grep -o -E '\.[^.\/]+$' | sort -u - person mMontu; 09.12.2013
comment
Согласованный. Я немного расслабился там. Редактирую свой ответ, чтобы исправить обнаруженную вами ошибку. - person gkb0986; 09.12.2013
comment
здорово. Я меняю кавычки на двойные кавычки, обновляю grep библиотеки и зависимости (потому что предоставленный git устарел), и теперь это работает под окнами. чувствую себя пользователем Linux. - person msangel; 21.04.2015
comment
Мне нравится такой подход. Просто немного изменил бы регулярное выражение $ find . -type f | grep -Eo '\.(\w+)$' | sort -u. Исходный показывает файлы без расширения, в моем случае это было не то, что мне нужно. - person Fernando Crespo; 17.03.2021

Я попробовал здесь несколько ответов, даже лучший ответ. Все они не соответствовали тому, что мне было нужно. Итак, помимо последних 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

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

Обновление: длинные расширения файлов Per @ alpha_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 - длина расширений файла, которые нужно включить, а затем найти любые расширения, превышающие эту длину.

person Shinrai    schedule 26.05.2014
comment
Является ли счетная версия рекурсивной? - person Fernando Montoya; 03.02.2016
comment
@Shinrai, в целом работает хорошо. но если у вас есть несколько случайных расширений файлов, которые действительно длинные, такие как .download, он разбивает .download на 2 части и сообщает о 2 файлах, один из которых загружен, а другой - рекламный - person alpha_989; 09.12.2017
comment
@ alpha_989, это из-за регулярного выражения [[: alpha:]] {3,6} также вызовет проблему с расширениями, длина которых меньше 3 символов. Отрегулируйте то, что вам нужно. Лично я бы сказал, что 2,16 должны работать в большинстве случаев. - person Shinrai; 04.04.2018
comment
Спасибо за ответ .. Да .. это то, что я понял позже. Он работал хорошо после того, как я изменил его, как вы упомянули. - person alpha_989; 04.04.2018

В 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)
person Andres Restrepo    schedule 24.08.2012

Поскольку уже существует другое решение, использующее 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)"
person ChristopheD    schedule 04.12.2009

Ни один из ответов до сих пор не рассматривает имена файлов с новой строкой должным образом (за исключением 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
person Community    schedule 04.12.2009

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

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

Он модифицирован 3-м способом ChristopheD.

person Robert    schedule 13.02.2018

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

find . -type f -exec sh -c 'echo "${0##*.}"' {} \; | sort | uniq -c
person Dmitry B.    schedule 21.05.2018
comment
Это, вероятно, будет довольно медленным из-за создания нового процесса для каждого файла. - person Ondra Žižka; 23.03.2019

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

find . -type f -name "*.php" -exec PATHTOAPP {} +
person jrock2004    schedule 25.03.2013

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

   # 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
person Diego Callejo    schedule 20.02.2020

В принятом ответе используется 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

person Chris Medina    schedule 04.04.2020

По-другому:

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

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

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

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

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

person Rajib    schedule 31.05.2021