Jak znaleźć wszystkie różne rozszerzenia plików w hierarchii folderów?

235

Na komputerze z systemem Linux chciałbym przejrzeć hierarchię folderów i uzyskać listę wszystkich różnych rozszerzeń plików w jej obrębie.

Jaki byłby najlepszy sposób na osiągnięcie tego z powłoki?

GloryFish
źródło

Odpowiedzi:

347

Spróbuj tego (nie jestem pewien, czy to najlepszy sposób, ale działa):

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

Działa w następujący sposób:

  • Znajdź wszystkie pliki z bieżącego folderu
  • Wyświetla rozszerzenie plików, jeśli takie istnieją
  • Stwórz unikalną posortowaną listę
Ivan Nevostruev
źródło
8
tylko w celach informacyjnych: jeśli chcesz wykluczyć niektóre katalogi z wyszukiwania (np. .svn), użyj find . -type f -path '*/.svn*' -prune -o -print | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u źródła
Dennis Golomazov
Spacje nie będą miały znaczenia. Każda nazwa pliku będzie w osobnym wierszu, więc separatorem listy plików będzie „\ n”, a nie spacja.
Ivan Nevostruev
1
W systemie Windows działa to lepiej i jest znacznie szybsze niż find: dir / s / b | perl -ne 'print 1 $ if m /\.([^^.\\\\]+)$/' | sort -u
Ryan Shillington
3
git odmiana odpowiedzi: użyj git ls-tree -r HEAD --name-onlyzamiastfind
jakub.g
8
Odmiana, pokazuje listę z find . -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort | uniq -c | sort -n
liczbami
54

Nie potrzeba do rury sort, awk można zrobić wszystko:

find . -type f | awk -F. '!a[$NF]++{print $NF}'
SiegeX
źródło
Nie działam jako alias, dostaję awk: błąd składniowy w kontekście linii źródłowej 1 to >>>! A [] <<< awk: ratowanie w linii źródłowej 1. Co robię źle? Mój alias jest zdefiniowany w następujący sposób: alias file_ext = "find. -Type f -name ' . ' | Awk -F. '! A [$ NF] ++ {print $ NF}'”
user2602152
2
@ user2602152 problem polega na tym, że próbujesz otoczyć całą linijkę cudzysłowami dla aliaspolecenia, ale samo polecenie już używa cudzysłowów w poleceniu find. Aby to naprawić, bashalias file_ext=$'find . -type f -name "*.*" | awk -F. \'!a[$NF]++{print $NF}\''
użyłbym
to nie działa, jeśli jeden podkatalog ma. w nazwie, a plik nie ma rozszerzenia. Przykład: kiedy uciekniemy z maindir, to się nie powiedziemaindir/test.dir/myfile
Nelson Teixeira,
1
@NelsonTeixeira Dodaj -printf "%f\n"na końcu polecenia „znajdź” i ponownie uruchom test.
SiegeX
41

Wersja rekurencyjna:

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

Jeśli chcesz mieć sumy (jak może być widoczne rozszerzenie):

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

Brak rekurencji (pojedynczy folder):

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

Oparłem to na tym wpisie na forum , kredyt powinien się tam znaleźć.

ChristopheD
źródło
Wspaniały! działa również w moim scenariuszu git, próbowałem dowiedzieć się, jakiego rodzaju plików dotknąłem w ostatnim zatwierdzeniu:git show --name-only --pretty="" | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort -u
vulcan raven
30

PowerShell:

dir -recurse | select-object extension -unique

Dzięki http://kevin-berridge.blogspot.com/2007/11/windows-powershell.html

Simon R.
źródło
20
OP powiedział „Na maszynie z systemem Linux”
Forbesmyester,
9
właściwie jest teraz prowershell dla Linuksa: github.com/Microsoft/PowerShell-DSC-for-Linux
KIC
4
Jak napisano, spowoduje to również wybranie katalogów, które mają .w nich (np. jquery-1.3.4Pokażą się jak .4na wyjściu). Zmień, aby dir -file -recurse | select-object extension -uniqueuzyskać tylko rozszerzenia plików.
mcw
1
@Forbesmyester: Osoby z Windows (takie jak ja) znajdą to pytanie na. Jest to przydatne.
Roel
1
Dzięki za odpowiedź w PowerShell. Nie zakładasz, jak użytkownicy wyszukują. Wiele osób głosowało z jakiegoś powodu
Mahesh
20

Moja bezkompromisowa, bez sed, bez Perla, bez Pythona alternatywa zgodna z POSIX:

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

Sztuka polega na tym, że odwraca on linię i odcina rozszerzenie na początku.
Konwertuje również rozszerzenia na małe litery.

Przykładowe dane wyjściowe:

   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
Ondra Žižka
źródło
na Macu, uniqnie ma pełnej flagi --count, ale -cdziała dobrze
worc
12

Znajdź wszystko za pomocą kropki i pokaż tylko przyrostek.

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

jeśli wiesz, że wszystkie przyrostki mają 3 znaki, to

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

lub z sesem pokazuje wszystkie sufiksy od jednego do czterech znaków. Zmień {1,4} na zakres znaków, których oczekujesz w sufiksie.

find . -type f | sed -n 's/.*\.\(.\{1,4\}\)$/\1/p'| sort -u
użytkownik224243
źródło
1
Awk nie musi „sortować” potoku, awk może zrobić wszystko: znaleźć. -type f -name " . " | awk -F. „! a [$ NF] ++ {print $ NF}”
SiegeX
@ SiegeX Twoja powinna być osobną odpowiedzią. Okazało się, że to polecenie działa najlepiej w przypadku dużych folderów, ponieważ drukuje rozszerzenia w miarę ich znajdowania. Należy jednak pamiętać, że powinno to być: -nazwa „ .
Ralf
@Ralf gotowe, opublikowałem odpowiedź tutaj . Nie jestem do końca pewien, co masz na myśli -name ".", ponieważ tak już jest
SiegeX
Miałem na myśli, że powinna to być -name „*. *”, Ale StackOverflow usuwa * znaki, co prawdopodobnie zdarzyło się również w twoim komentarzu.
Ralf
Wydaje się, że powinna to być zaakceptowana odpowiedź, awk jest lepszy niż perl jako narzędzie wiersza poleceń i obejmuje filozofię uniksowania polegającą na łączeniu małych programów interoperacyjnych w spójne i czytelne procedury.
Jon z
7

Dodanie własnej odmiany do miksu. Myślę, że jest to najprostszy z możliwych i może być użyteczny, gdy wydajność nie stanowi dużego problemu.

find . -type f | grep -o -E '\.[^\.]+$' | sort -u
gkb0986
źródło
1
+1 za przenośność, chociaż regex jest dość ograniczony, ponieważ pasuje tylko do rozszerzeń składających się z jednej litery. Użycie wyrażenia regularnego z zaakceptowanej odpowiedzi wydaje się lepsze:$ find . -type f | grep -o -E '\.[^.\/]+$' | sort -u
mMontu
1
Zgoda. Troszkę się rozluźniłem. Edytowanie mojej odpowiedzi, aby naprawić zauważony błąd.
gkb0986,
chłodny. Chenge cytaty do podwójnych cytatów, aktualizuję biraria grep i zależności (ponieważ dostarczone z git jest nieaktualne), a teraz to działa pod Windows. czuję się jak użytkownik systemu Linux.
msangel
5

W Pythonie używanie generatorów dla bardzo dużych katalogów, w tym pustych rozszerzeń, i uzyskiwanie liczby wyświetleń każdego rozszerzenia:

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)
Andres Restrepo
źródło
5

Próbowałem tutaj wielu odpowiedzi, nawet „najlepszych”. Wszyscy wymyślili coś, czego nie chciałem. Oprócz ostatnich 12 godzin siedzenia w kodzie wyrażeń regularnych dla wielu programów oraz czytania i testowania tych odpowiedzi, to właśnie wymyśliłem, który działa DOKŁADNIE tak, jak chcę.

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort -u
  • Znajduje wszystkie pliki, które mogą mieć rozszerzenie.
  • Greps tylko rozszerzenie
  • Greps dla rozszerzeń plików o długości od 2 do 16 znaków (po prostu dostosuj liczby, jeśli nie odpowiadają twoim potrzebom). Pomaga to uniknąć plików pamięci podręcznej i plików systemowych (bit pliku systemowego służy do wyszukiwania w więzieniu).
  • Awk, aby wydrukować rozszerzenia małymi literami.
  • Sortuj i wprowadzaj tylko unikalne wartości. Początkowo próbowałem wypróbować odpowiedź na awk, ale spowoduje to podwójne wydrukowanie elementów, które różnią się w zależności od wielkości liter.

Jeśli potrzebujesz liczby rozszerzeń plików, użyj poniższego kodu

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

Chociaż wykonanie tych metod zajmie trochę czasu i prawdopodobnie nie są to najlepsze sposoby rozwiązania problemu, działają one.

Aktualizacja: Rozszerzenia plików Per @ alpha_989 spowodują problem. Wynika to z pierwotnego wyrażenia regularnego „[[: alpha:]] {3,6}”. Zaktualizowałem odpowiedź, dodając wyrażenie „[[: alpha:]] {2,16}”. Jednak każdy, kto używa tego kodu, powinien mieć świadomość, że liczby te są minimalną i maksymalną długością dozwolonego rozszerzenia dla końcowego wyniku. Wszystko poza tym zakresem zostanie podzielone na wiele wierszy na wyjściu.

Uwaga: w oryginalnym poście było napisane „- Greps dla rozszerzeń plików od 3 do 6 znaków (po prostu dostosuj liczby, jeśli nie pasują do twoich potrzeb). Pomaga to uniknąć plików pamięci podręcznej i plików systemowych (bit pliku systemowego służy do wyszukiwania w więzieniu). „

Pomysł: może być używany do znajdowania rozszerzeń plików o określonej długości za pomocą:

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

Gdzie 4 to długość rozszerzeń plików, które należy uwzględnić, a następnie znajdź także wszelkie rozszerzenia poza tą długością.

Shinrai
źródło
Czy wersja zliczająca jest rekurencyjna?
Fernando Montoya,
@Shinrai, Ogólnie działa dobrze. ale jeśli masz jakieś losowe rozszerzenia plików, które są naprawdę długie, takie jak .download, podzieli „.download” na 2 części i zgłosi 2 pliki, z których jeden to „downlo”, a drugi to „ad”
alpha_989
@ alpha_989, Jest to spowodowane wyrażeniem regularnym „[[: alpha:]] {3,6}” spowoduje również problem z rozszerzeniami mniejszymi niż 3 znaki. Dostosuj się do tego, czego potrzebujesz. Osobiście powiedziałbym, że 2,16 powinno działać w większości przypadków.
Shinrai,
Dzięki, że odpowiedziałeś ... Tak ... właśnie to sobie uświadomiłem. Działa dobrze po tym, jak zmodyfikowałem go podobnie do tego, o czym wspomniałeś.
alpha_989
3

Ponieważ istnieje już inne rozwiązanie korzystające z Perla:

Jeśli masz zainstalowany Python, możesz również zrobić (z powłoki):

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)"
ChristopheD
źródło
2

Żadna z dotychczasowych odpowiedzi nie dotyczy poprawnie nazw plików z nowymi wierszami (z wyjątkiem ChristopheD, które właśnie pojawiły się podczas pisania tego tekstu). Poniższy przykład nie jest pojedynczą linią powłoki, ale działa i jest dość szybki.

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

źródło
2

Nie sądzę, żeby ten był jeszcze wspomniany:

find . -type f -exec sh -c 'echo "${0##*.}"' {} \; | sort | uniq -c
Dmitry B.
źródło
Prawdopodobnie byłoby to dość powolne ze względu na tworzenie nowego procesu dla każdego pliku.
Ondra Žižka
1

Myślę, że najprostszym i najprostszym sposobem jest

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

Jest modyfikowany na 3. sposób ChristopheD.

Robert
źródło
0

możesz to zrobić

find . -type f -name "*.php" -exec PATHTOAPP {} +
jrock2004
źródło
0

Znalazłem to proste i szybkie ...

   # 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
Diego Callejo
źródło
0

Zaakceptowana odpowiedź używa REGEX i nie możesz utworzyć polecenia aliasu za pomocą REGEX, musisz umieścić go w skrypcie powłoki, używam Amazon Linux 2 i wykonałem następujące czynności:

  1. Wstawiam zaakceptowany kod odpowiedzi do pliku, używając:

    sudo vim find.sh

dodaj ten kod:

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

zapisz plik, wpisując: :wq!

  1. sudo vim ~/.bash_profile

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

  3. :wq!

  4. . ~/.bash_profile

Chris Medina
źródło