Як я можу знайти всі окремі розширення файлів в ієрархії папок?


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 це працює краще і набагато швидше, ніж знайти: dir / s / b | perl -ne 'надрукувати $ 1, якщо m /\.( evidence^^.\\\\Sense+)$/' | сорт -у
Райан Шиллінгтон


8
Варіація, це показує список з підрахунком за розширення:find . -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort | uniq -c | sort -n
marcovtwout

54

Немає необхідності в трубі 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 [$ NF] ++ {print $ NF}'"
user2602152

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

це не працює, якщо в одному піддіректорі є. в його імені, і файл не має розширення. Приклад: коли ми перебігаємо з Maindir, це не вдасться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
насправді є lwers для 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

Моя безвідмовна, без сед, без 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

на 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 -ім'я " . " | awk -F. '! a [$ NF] ++ {print $ NF}'
SiegeX

@SiegeX Ваша відповідь має бути окремою. Він виявив, що команда працює найкраще для великих папок, оскільки вона друкує розширення у міру їх знаходження. Але зауважте, що це має бути: -name " . "
Ральф

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

Я мав на увазі, що це має бути -name "*. *", Але StackOverflow видаляє * символи, що, ймовірно, трапилось і у вашому коментарі.
Ральф

Здається, це має бути прийнятою відповіддю, awk бажано perl як інструмент командного рядка, і він охоплює єдину філософію об'єднання малих інтероперабельних програм у згуртовані та читані процедури.
Jon z

7

Додавання власної варіації до суміші. Я думаю, що це найпростіше з партії і може бути корисним, коли ефективність не викликає особливих проблем.

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

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

1
Домовились. Я трохи відтупав. Редагування моєї відповіді, щоб виправити помилку, яку ви виявили.
gkb0986

круто. Я цитую цитати на подвійні котирування, оновлюю греп- бірарі та залежності (тому що надається git застаріло), і тепер це працює під Windows. відчувати себе користувачем 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
  • Знаходить усі файли, які можуть мати розширення.
  • Схоплює лише розширення
  • Знімки для розширення файлів від 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

Хоча ці методи потребують певного часу, і, ймовірно, не найкращі способи вирішити цю проблему, вони працюють.

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

Примітка. Оригінальна публікація прочитала "- Знімки для розширення файлів між 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}" також спричинить проблему з розширеннями менше трьох символів. Налаштуйте те, що вам потрібно. Особисто я б сказав, що 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

Можливо, це буде досить повільним через нерестування нового процесу для кожного файлу.
Ondra Žižka

1

Я думаю, найпростіший і найпростіший спосіб

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

Він модифікований на третьому шляху ChristopheD.


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.