Znajdź liczbę plików dla każdego rozszerzenia w katalogu


10

Chcę policzyć liczbę plików dla każdego rozszerzenia w katalogu, a także pliki bez rozszerzenia.

Wypróbowałem kilka opcji, ale nie znalazłem jeszcze działającego rozwiązania:

  • find "$folder" -type f | sed 's/.*\.//' | sort | uniq -cjest opcją, ale nie działa, jeśli nie ma rozszerzenia pliku. Muszę wiedzieć, ile plików nie ma rozszerzenia.

  • Próbowałem również znaleźć pętlę find w tablicy, a następnie zsumować wyniki, ale w tym momencie ten kod zgłasza niezadeklarowany błąd zmiennej, ale tylko poza pętlą:

    declare -a arr
    arr=()
    echo ${arr[@]}
    

    Zgłasza to niezadeklarowaną zmienną, a także po zakończeniu pętli wyszukiwania.

Odpowiedzi:


10
find "$path" -type f | sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' | LC_COLLATE=C sort | uniq -c

Wyjaśnienie:

  • find "$path" -type f uzyskać rekurencyjną listę wszystkich plików w "$path"folderze.
  • sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' wyrażenia regularne:
    • /.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/ zamień wszystkie pliki bez rozszerzenia na (brak).
    • s/.*\.// uzyskać rozszerzenie pozostałych plików.
  • LC_COLLATE=C sort posortuj wynik, trzymając symbole na górze.
  • uniq -c policzyć liczbę powtórzonych wpisów.

9

Za pomocą Pythona:

import os
from collections import Counter
from pprint import pprint

lst = []
for file in os.listdir('./'):
        name, ext = os.path.splitext(file)
        lst.append(ext)

pprint(Counter(lst))

Wyjście:

Counter({'': 7,
         '.png': 4,
         '.mp3': 3,
         '.jpg': 3,
         '.mkv': 3,
         '.py': 1,
         '.swp': 1,
         '.sh': 1})

Prawdopodobnie możesz uciec od rozumienia listy, na przykład ext = [ f.split('.')[-1] for f in os.listdir('./') ] Thatll skraca kilka linii i może jest bardziej Pythonic
Sergiy Kolodyazhnyy

Dzięki za sugestie, próbowałem napisać to tak jasno, jak tylko mogłem ...
Ravexina,

1
Przejrzystość jest zaletą :) Zwłaszcza jeśli chodzi o kod i dokumentację inżynierską.
Sergiy Kolodyazhnyy

6

Jeśli masz GNU awk, możesz zrobić coś takiego

printf '%s\0' * | gawk 'BEGIN{RS="\0"; FS="."; OFS="\t"} 
  {a[(NF>1 ? $NF : "(none)")]++} 
  END{for(i in a) print a[i],i}
'

tj. konstruuj / zwiększaj tablicę asocjacyjną wpisaną w ostatnim .oddzielonym polu lub dowolny ustalony ciąg znaków, na przykład (none)jeśli nie ma rozszerzenia.

mawkwydaje się nie dopuszczać separatora rekordów zerowych - możesz użyć mawkdomyślnego separatora nowej linii, jeśli masz pewność, że nie musisz zajmować się znakami nowej linii w nazwach plików:

printf '%s\n' * | mawk 'BEGIN{FS="."; OFS="\t"} {a[(NF>1 ? $NF : "(none)")]++} END{for(i in a) print a[i],i}'

5

Z podstawowym, /bin/sha nawet bashzadaniem może być trochę trudne, ale jak widać w innych odpowiedziach, narzędzia, które mogą pracować na agregowanych danych, mogą szczególnie łatwo poradzić sobie z takim zadaniem. Jednym z takich narzędzi byłaby sqlitebaza danych.

Bardzo prostym procesem korzystania z sqlitebazy danych byłoby utworzenie .csvpliku z dwoma polami: nazwą pliku i rozszerzeniem. Później sqlitemożna użyć prostego zbiorczą deklarację COUNT()ze GROUP BY extprzeprowadzić liczenie plików na podstawie rozszerzenia pola

$ { printf "file,ext\n"; find -type f -exec sh -c 'f=${1##*/};printf "%s,%s\n" "${1}" "${1##*.}"' sh {} \; ; }  > files.csv
$ sqlite3 <<EOF
> .mode csv
> .import ./files.csv files_tb
> SELECT ext,COUNT(file) FROM files_tb GROUP BY ext;
> EOF
csv,1
mp3,6
txt,1
wav,27

files_tbtabela, o której myślę, że jest przywoływana, ale kolumny tabeli nie są zdefiniowane nigdzie, co widzę?
WinEunuuchs2Unix

@ WinEunuuchs2Unix Są one zdefiniowane w samym pliku csv. To właśnie printfrobi pierwszy . A SQLite domyślnie traktuje pierwszą linię pliku csv jako nazwy kolumn.
Sergiy Kolodyazhnyy

1
Bardzo imponujące! +1
WinEunuuchs2Unix

5

Używanie programu PowerShell, jeśli jest to opcja:

Get-ChildItem -File | Group-Object Extension -NoElement

lub krócej, używając aliasów:

ls -file | group -n Extension

1
Łał! Świetna pierwsza odpowiedź! Nawet nie wiedziałem, że PowerShell istnieje dla Linuksa ... +1
Fabby

2
Dzięki. Przez pewien czas istniał na wielu platformach i jako oprogramowanie typu open source, ale na SO i SU pojawił się wzorzec, w którym na pytania dotyczące skryptów powłoki w systemie Windows często odpowiadano: „Cóż, zainstaluj cygwin i użyj bash, a następnie możesz wykonać następujące czynności ”, więc wahałem się czynić to samo w przypadku witryn Linux SE z narzędziami pochodzącymi z systemu Windows. Było to jednak miłe zadanie, które dość dobrze pokazuje mocne strony PowerShell, bez odwoływania się do starego argumentu na temat gadatliwości.
Joey,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.