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


235

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

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

Ответы:


347

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

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

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

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

8
просто для справки: если вы хотите исключить некоторые каталоги из поиска (например .svn), используйте find . -type f -path '*/.svn*' -prune -o -print | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u источник
Деннис Голомазов

Пространства не будут иметь никакого значения. Каждое имя файла будет находиться в отдельной строке, поэтому разделителем списка файлов будет «\ n», а не пробел.
Иван Невоструев

1
В Windows это работает лучше и намного быстрее, чем find: dir / s / b | perl -ne 'печатает $ 1, если m /\.([^^.\\\\]+)$/' | sort -u
Райан Шиллингтон


8
Вариант, это показывает список с количеством расширений:find . -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort | uniq -c | sort -n
marcovtwout

55

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

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

Я не получаю это для работы в качестве псевдонима, я получаю awk: синтаксическая ошибка в контексте строки 1 источника >>>! A [] <<< awk: выход из строя в строке источника 1. Что я делаю неправильно? Мой псевдоним определяется следующим образом: псевдоним file_ext = "find. -Type f -name ' . ' | Awk -F. '!
A

2
@ user2602152 проблема в том, что вы пытаетесь заключить в одну строку весь кавычки для aliasкоманды, но сама команда уже использует кавычки в команде поиска. Чтобы исправить это, я бы использовал bashсинтаксис буквальной строки следующим образом:alias file_ext=$'find . -type f -name "*.*" | awk -F. \'!a[$NF]++{print $NF}\''
SiegeX

это не сработает, если у одного subdir есть. в его имени, и файл не имеет расширения файла. Пример: когда мы бежим из Маиндира, он потерпит неудачуmaindir/test.dir/myfile
Нельсон Тейшейра

1
@NelsonTeixeira Добавьте -printf "%f\n"в конец команду 'find' и повторите тест.
SiegeX

41

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

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

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


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

30

Powershell:

dir -recurse | select-object extension -unique

Благодаря http://kevin-berridge.blogspot.com/2007/11/windows-powershell.html


20
ОП сказал «На машине с Linux»
Forbesmyester

9
на самом деле есть версия для Linux: github.com/Microsoft/PowerShell-DSC-for-Linux
KIC,

4
Как написано, это также подберет каталоги, .в которых есть (например, jquery-1.3.4будет отображаться как .4в выходных данных). Перейдите на, dir -file -recurse | select-object extension -uniqueчтобы получить только расширения файлов.
MCW

1
@ Forbesmyester: Люди с Windows (как и я) найдут этот вопрос. Так что это полезно.
Roel

1
Спасибо за ответ Powershell. Вы не предполагаете, как пользователи ищут. Многие люди проголосовали за причину
Махеш

20

Моя альтернатива, не нуждающаяся в awk, sed и Perl, POSIX-совместимая с 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

на Mac uniqне имеет полного флага --count, но -cработает просто отлично
worc

12

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

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

1
Нет необходимости в сортировке канала, awk может сделать все: найти. -тип f -name " . " | awk -F. '! a [$ NF] ++ {print $ NF}'
SiegeX

@SiegeX Ваш ответ должен быть отдельным. Он обнаружил, что эта команда лучше всего работает для больших папок, так как печатает расширения по мере их нахождения. Но обратите внимание, что это должно быть: -name " . "
Ральф

@Ralf готово, опубликовал ответ здесь . Не совсем уверен, что вы подразумеваете под этой -name "."вещью, потому что это то, что она уже есть
SiegeX

Я имел в виду, что это должно быть -name "*. *", Но StackOverflow удаляет символы *, что, вероятно, и в вашем комментарии.
Ральф

Похоже, что это должен быть принятый ответ, awk предпочтительнее perl в качестве инструмента командной строки, и он охватывает философию Unix, заключающуюся в том, чтобы объединять небольшие совместимые программы в связные и удобочитаемые процедуры.
Jon Z

7

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

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

1
+1 для переносимости, хотя регулярное выражение довольно ограничено, так как оно соответствует только расширениям, состоящим из одной буквы. Использование регулярного выражения из принятого ответа кажется лучше:$ find . -type f | grep -o -E '\.[^.\/]+$' | sort -u
mMontu

1
Согласовано. Я немного расслабился там. Редактирую мой ответ, чтобы исправить ошибку, которую вы заметили.
gkb0986

прохладный. Я изменяю кавычки на двойные кавычки, обновляю библиотеки и зависимости grep (потому что предоставляемый git устарел), и теперь эта работа под окнами. чувствую себя пользователем Linux.
msangel

5

В 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)

5

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


Является ли версия счета рекурсивной?
Фернандо Монтойя

@Shinrai, в целом работает хорошо. но если у вас есть случайные расширения файлов, которые действительно длинные, такие как .download, он разбьет «.download» на 2 части и сообщит о 2 файлах, один из которых «downlo», а другой «ad»
alpha_989

@ alpha_989, это из-за того, что регулярное выражение "[[: alpha:]] {3,6}" также вызовет проблему с расширениями меньше 3 символов. Настройтесь на то, что вам нужно. Лично я бы сказал, что 2,16 должно работать в большинстве случаев.
Shinrai

Спасибо за ответ .. Да .. это то, что я понял позже. Это сработало хорошо после того, как я изменил его так, как вы упомянули.
alpha_989

3

Так как уже есть другое решение, которое использует 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)"

2

Ни один из ответов на данный момент не имеет отношения к именам файлов с символами новой строки должным образом (за исключением 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

2

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

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

Это может быть довольно медленным из-за запуска нового процесса для каждого файла.
Ондра Жижка

1

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

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

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


0

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

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

0

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

   # 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

0

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.