Знайдіть кількість файлів для кожного розширення в каталозі


10

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

Я спробував кілька варіантів, але ще не знайшов робочого рішення:

  • find "$folder" -type f | sed 's/.*\.//' | sort | uniq -cце варіант, але не працює, якщо розширення файлу немає. Мені потрібно знати, скільки файлів не мають розширення.

  • Я також спробував знайти цикл пошуку в масив і потім підсумувати результати, але в цей час цей код видає помилку, що не визначається змінною, але лише поза циклу:

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

    Це викидає незадекларовану змінну, а також як тільки цикл знаходження завершиться.

Відповіді:


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

Пояснення:

  • find "$path" -type f отримати рекурсивний перелік усіх файлів у "$path"папці.
  • sed -e '/.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/' -e 's/.*\.//' регулярні вирази:
    • /.*\/[^\/]*\.[^\/]*$/!s/.*/(none)/ замініть всі файли без розширення на (none).
    • s/.*\.// отримати розширення решти файлів.
  • LC_COLLATE=C sort сортуйте результат, зберігаючи символи вгорі.
  • uniq -c підрахувати кількість повторних записів.

9

Використання Python:

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

Вихід:

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

Напевно, ви можете піти з розуміння списку, як, наприклад, ext = [ f.split('.')[-1] for f in os.listdir('./') ] Thatll зробить його на пару ліній коротшими і, можливо, більше Pythonic
Сергій Колодяжний

Дякую за пропозицію, я просто намагався написати це як можна зрозуміліше
Ravexina

1
Чіткість - це чеснота :) Особливо якщо мова йде про код та інженерну документацію.
Сергій Колодяжний

6

Якщо у вас є GNU awk, ви можете зробити щось подібне

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

тобто будують / збільшують асоціативний масив, введений в останнє .відокремлене поле, або якусь довільну фіксовану рядок, наприклад, (none)якщо немає розширення.

mawkСхоже, не дозволяє розділити запис з нульовим байтом - ви можете використовувати mawkз роздільником нового рядка за замовчуванням, якщо ви впевнені, що вам не потрібно мати справу з новими рядками у назвах файлів:

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

5

З основним /bin/shабо навіть bashзавданням може бути трохи складно, але як ви бачите в інших відповідях, інструменти, які можуть працювати над сукупними даними, можуть впоратися з таким завданням особливо легко. Одним із таких інструментів буде sqliteбаза даних.

Дуже простим процесом використання sqliteбази даних було б створення .csvфайлу з двома полями: ім'ям файлу та розширенням. Пізніше sqliteможна використовувати просте сукупне заяву COUNT()з GROUP BY extдля виконання підрахунку файлів на основі розширення поля

$ { 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_tbТаблиця, на яку я думаю, на яку посилаються, але стовпці таблиці не визначені ніде я можу бачити?
WinEunuuchs2Unix

@ WinEunuuchs2Unix Вони визначені у самому файлі csv. Ось що printfробить перший . І SQLite за замовчуванням буде обробляти перший рядок файлу CSV як назви стовпців.
Сергій Колодяжний

1
Дуже вражає! +1
WinEunuuchs2Unix

5

Використання PowerShell, якщо це варіант:

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

або коротше, використовуючи псевдоніми:

ls -file | group -n Extension

1
Оце Так! Чудова перша відповідь! Я навіть не знав, що PowerShell існує для Linux ... +1
Fabby

2
Дякую. Він деякий час існував міжплатформним та відкритим кодом, але існував зразок на SO та SU, де на запитання сценаріїв оболонок у Windows часто відповідали "Ну, встановіть cygwin і використовуйте bash, тоді ви можете зробити наступне ", тож я вагаюся зробити те ж саме для сайтів Linux SE з інструментами, що виникли в Windows. Але це було приємним завданням, яке досить сильно показує сили PowerShell, не запрошуючи старого аргументу про багатослівність.
Джої
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.