Bir klasör hiyerarşisinde tüm farklı dosya uzantılarını nasıl bulabilirim?


235

Bir Linux makinesinde bir klasör hiyerarşisinde gezinmek ve içindeki farklı dosya uzantılarının bir listesini almak istiyorum.

Bunu bir kabuktan başarmanın en iyi yolu ne olurdu?

Yanıtlar:


347

Bunu deneyin (en iyi yol olup olmadığından emin değilim, ama işe yarıyor):

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

Aşağıdaki gibi çalışır:

  • Geçerli klasördeki tüm dosyaları bul
  • Varsa dosyaların uzantısını yazdırır
  • Benzersiz bir sıralı liste yapın

8
sadece referans için: bazı dizinleri arama (örneğin .svn) dışında tutmak istiyorsanız , find . -type f -path '*/.svn*' -prune -o -print | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u kaynak
Dennis Golomazov

Alanlar hiçbir fark yaratmaz. Her dosya adı ayrı bir satırda olacaktır, bu nedenle dosya listesi sınırlayıcısı boşluk değil "\ n" olacaktır.
Ivan Nevostruev

1
Windows'da, bu daha iyi çalışır ve bulmaktan çok daha hızlıdır: dir / s / b | perl -ne 'm /\.([^^.\\\\\++)$/' e $ 1 yazdır | sort -u
Ryan Shillington


8
Bir varyasyon, bu, uzantı başına sayıları içeren listeyi gösterir:find . -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort | uniq -c | sort -n
marcovtwout

55

Boruya gerek yok sort, awk her şeyi yapabilir:

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

Bu bir takma ad olarak çalışmak için elde edemiyorum, ben kaynak hattı 1 bağlamında awk: sözdizimi hatası >>>! A [] <<< awk: kaynak satır 1 kurtarma. Ne yanlış yapıyorum? Takma adım şöyle tanımlanır: takma ad file_ext = "bul. -Type f -name ' . ' | Awk -F. '! A [$ NF] ++ {print $ NF}'"
user2602152

2
@ user2602152 sorun, aliaskomut için tırnak işaretleri ile tek satırın tamamını çevrelemeye çalışmanızdır, ancak komutun kendisi zaten find komutunda tırnak işaretleri kullanır. Bunu düzeltmek için bash's literal dize sözdizimini şöyle kullanırdım :alias file_ext=$'find . -type f -name "*.*" | awk -F. \'!a[$NF]++{print $NF}\''
SiegeX

bir alt dizinde a varsa bu çalışmaz. adında ve dosyada dosya uzantısı yok. Örnek: maindir'den koştuğumuzda başarısız olurmaindir/test.dir/myfile
Nelson Teixeira

1
@NelsonTeixeira -printf "%f\n"'find' komutunun sonuna ekleyin ve testinizi yeniden çalıştırın.
SiegeX

41

Özyinelemeli sürüm:

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

Toplamlar istiyorsanız (uzantının nasıl göründüğü):

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

Özyinelemesiz (tek klasör):

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

Ben bu forum yazı üzerine dayanıyorum , kredi oraya gitmek gerekir.


Harika! benim git senaryom için de çalışıyor, son taahhütte hangi dosyalara dokunduğumu anlamaya çalışıyordu:git show --name-only --pretty="" | sed -e 's/.*\.//' | sed -e 's/.*\///' | sort -u
vulcan raven

30

Güç kalkanı:

dir -recurse | select-object extension -unique

Http://kevin-berridge.blogspot.com/2007/11/windows-powershell.html sayesinde


20
OP "Bir Linux makinesinde" dedi
Forbesmyester

9
aslında şimdi linux için prowershell var: github.com/Microsoft/PowerShell-DSC-for-Linux
KIC

4
Yazıldığı gibi, bu, içinde bir .olan dizinleri de alır (örneğin çıktıdaki jquery-1.3.4gibi görünecektir .4). dir -file -recurse | select-object extension -uniqueYalnızca dosya uzantılarını almak için olarak değiştirin .
mcw

1
@Forbesmyester: Windows'lu insanlar (benim gibi) bu soruyu bulacaktır. Yani bu yararlı.
Roel

1
Powershell cevabı için teşekkürler. Kullanıcıların nasıl arama yaptığını varsaymazsınız. Birçok insan bir nedenden ötürü seçildi
Mahesh

20

Awk-less, sed-less, Perl-less, Python'suz POSIX uyumlu alternatifim:

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

Hüner, çizgiyi tersine çevirip başlangıçta uzantıyı kesmesidir.
Ayrıca uzantıları küçük harfe dönüştürür.

Örnek çıktı:

   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'te, uniqtam bayrağı yok --count, ama iyi -cçalışıyor
worc

12

Her şeyi bir nokta ile bulun ve sadece soneki gösterin.

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

tüm son ekin 3 karakteri olduğunu biliyorsan

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

veya sed ile bir ila dört karakter içeren tüm sonekleri gösterir. {1,4} ile sonekde beklediğiniz karakter aralığını değiştirin.

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

1
Boru 'sıralamak' için gerek yok, awk her şeyi yapabilir: bulmak. tipi f-adı " . " | awk -F. '! a [$ NF] ++ {print $ NF}'
SiegeX

@SiegeX Sizinki ayrı bir cevap olmalı. Bu komutun, uzantıları buldukça yazdırdığı için büyük klasörler için en iyi şekilde çalıştığını buldu. Ancak şöyle olması gerektiğini unutmayın: -name " . "
Ralf

@Ralf bitti, burada cevap gönderdi . -name "."
Şeyle

-Name "*. *" Olması gerekiyordu, ancak StackOverflow muhtemelen yorumunuzda olan * karakterlerini kaldırır.
Ralf

Bu kabul edilmiş cevap olmalı gibi görünüyor, awk bir komut satırı aracı olarak perl için tercih edilir ve küçük birlikte çalışabilir programları uyumlu ve okunabilir prosedürlere borulamak unix felsefesini kucaklar.
Jon z

7

Karışıma kendi varyasyonumu ekliyorum. Bence bu en basit olanı ve verimlilik büyük bir endişe olmadığında yararlı olabilir.

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

1
Düzenlenebilirlik için +1, ancak normal ifade oldukça sınırlı olmasına rağmen, yalnızca tek bir harften oluşan uzantılarla eşleşir. Kabul edilen yanıttan normal $ find . -type f | grep -o -E '\.[^.\/]+$' | sort -u
ifadeyi kullanmak

1
Kabul. Orada biraz gevşedim. Saptadığınız hatayı düzeltmek için cevabımı düzenleme.
gkb0986

güzel. Ben tırnak çift tırnak, chrep biraries ve bağımlılık (git ile sağlanan eski olduğu için) güncellemek chenge ve şimdi bu çalışma windows altında. linux kullanıcısı gibi hissediyorum.
msangel

5

Python'da boş uzantılar da dahil olmak üzere çok büyük dizinler için jeneratörler kullanan ve her uzantının kaç kez görüntülendiğini gösteren:

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

Burada bir sürü cevap denedim, hatta "en iyi" yanıtı bile. Hepsi benim peşinde olduğum şeyden kısa bir süre geldi. Yani son 12 saat içinde birden fazla program için regex kodunda oturan ve bu cevapları okuyup test etmenin yanı sıra tam olarak istediğim gibi çalışan şey budur.

 find . -type f -name "*.*" | grep -o -E "\.[^\.]+$" | grep -o -E "[[:alpha:]]{2,16}" | awk '{print tolower($0)}' | sort -u
  • Uzantısı olabilecek tüm dosyaları bulur.
  • Yalnızca uzantıyı karşılıyor
  • 2 ila 16 karakter arasındaki dosya uzantıları için Greps (sadece ihtiyacınıza uygun değilse sayıları ayarlayın). Bu, önbellek dosyalarını ve sistem dosyalarını önlemeye yardımcı olur (sistem dosyası biti, hapishaneyi aramaktır).
  • Uzantıları küçük harflerle yazdırmak için awk.
  • Sırala ve sadece benzersiz değerleri getir. Başlangıçta awk cevabını denemeye çalıştım, ancak duyarlılık durumunda değişen öğeleri iki katına basardı.

Bir dizi dosya uzantısına ihtiyacınız varsa aşağıdaki kodu kullanın

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

Bu yöntemlerin tamamlanması biraz zaman alacaktır ve muhtemelen sorunla ilgili en iyi yol değildir, ancak işe yararlar.

Güncelleme: @ @ alpha_989 başına uzun dosya uzantıları soruna neden olur. Bunun nedeni, orijinal regex "[[: alpha:]] {3,6}". Cevabı, "[[: alpha:]] {2,16}" normal ifadesini içerecek şekilde güncelledim. Ancak bu kodu kullanan herkes, bu sayıların, son çıktı için uzantının izin verilen süresinin min ve maks olduğunu bilmelidir. Bu aralığın dışındaki her şey çıktıda birden çok satıra bölünecektir.

Not: Orijinal yazı okundu "- 3 ile 6 karakter arasında dosya uzantıları için Greps (sadece ihtiyacınıza uygun değilse sayıları ayarlayın). "

Fikir: Aşağıdaki yollarla belirli bir uzunluktaki dosya uzantılarını bulmak için kullanılabilir:

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

Burada 4, eklenecek dosya uzantıları uzunluğudur ve daha sonra bu uzunluktan sonraki uzantıları da bulur.


Sayım sürümü özyinelemeli mi?
Fernando Montoya

@Shinrai, Genel olarak iyi çalışıyor. ancak .download gibi gerçekten uzun bazı rasgele dosya uzantılarınız varsa, ".download" dosyasını 2 parçaya böler ve biri "downlo" diğeri "ad" olan 2 dosya bildirir
alpha_989

@ alpha_989, Bunun nedeni "[[: alpha:]] {3,6}" normal ifadesinin 3 karakterden küçük uzantılarda da soruna neden olması. İhtiyacınıza göre ayarlayın. Şahsen, çoğu durumda 2,16'nın çalışması gerektiğini söyleyebilirim.
Shinrai

Cevapladığınız için teşekkürler .. Evet .. sonra fark ettiğim şey bu. Bahsettiğinize benzer şekilde değiştirdikten sonra iyi çalıştı.
alpha_989

3

Perl kullanan başka bir çözüm olduğundan:

Yüklü Python varsa şunları da yapabilirsiniz (kabuktan):

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

Şimdiye kadar gelen yanıtların hiçbiri yeni satırlarla dosya adlarıyla düzgün bir şekilde ilgilenmiyor (bunu yazarken gelen ChristopheD'ler hariç). Aşağıdaki bir kabuk tek astar değil, işe yarıyor ve oldukça hızlı.

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

Bu henüz bahsedildi sanmıyorum:

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

Her dosya için yeni bir süreç ortaya çıkması nedeniyle bu muhtemelen oldukça yavaş olacaktır.
Ondra Žižka

1

Bence en basit ve anlaşılır yol

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

ChristopheD'in 3. yolunda değiştirildi.


0

bunu da yapabilirsin

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

0

Basit ve hızlı buldum ...

   # 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

Kabul edilen cevap REGEX kullanır ve REGEX ile bir diğer ad komutu oluşturamazsınız, bir kabuk betiğine koymanız gerekir, Amazon Linux 2 kullanıyorum ve aşağıdakileri yaptım:

  1. Kabul edilen cevap kodunu kullanarak bir dosyaya koydum:

    sudo vim find.sh

bu kodu ekle:

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

şunu yazarak dosyayı kaydedin: :wq!

  1. sudo vim ~/.bash_profile

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

  3. :wq!

  4. . ~/.bash_profile

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.