Policz pliki w katalogu według rozszerzenia


15

Do celów testowych chciałbym policzyć, ile plików obrazów znajduje się w katalogu, oddzielając każdy typ pliku obrazu według rozszerzenia pliku (jpg = „tak”. To dlatego, że później przyda się w innym skrypcie, który wykona akcję na każdym rozszerzeniu pliku). Czy mogę użyć czegoś takiego jak poniżej tylko do plików JPEG?

jpg=""
count=`ls -1 *.jpg 2>/dev/null | wc -l`
if [ $count != 0 ]
then
echo jpg files found: $count ; jpg="yes"
fi

Biorąc pod uwagę rozszerzenia plików jpg, png, bmp, raw i inne, czy powinienem to whilezrobić?

Odpowiedzi:


14

Sugerowałbym inne podejście, unikając możliwych problemów związanych z dzieleniem słów ls

#!/bin/bash

shopt -s nullglob

for ext in jpg png gif; do 
  files=( *."$ext" )
  printf 'number of %s files: %d\n' "$ext" "${#files[@]}"

  # now we can loop over all the files having the current extension
  for f in "${files[@]}"; do
    # anything else you like with these files
    :
  done 

done

Możesz zapętlić filestablicę dowolnymi innymi poleceniami, które chcesz wykonać na plikach poszczególnych rozszerzeń.


Bardziej przenośnie - lub w przypadku powłok, które nie udostępniają jawnie tablic - można ponownie użyć tablicy parametrów pozycyjnych powłoki, tj.

set -- *."$ext"

a następnie zamień ${#files[@]}i za ${files[@]}pomocą $#i"$@"


23

Moje podejście to:

  1. Wyświetl wszystkie pliki w katalogu
  2. Wyodrębnij ich rozszerzenie
  3. Posortuj wynik
  4. Policz wystąpienia każdego rozszerzenia

Coś w tym stylu (ostatnie awkwywołanie służy wyłącznie do formatowania):

ls -q -U | awk -F . '{print $NF}' | sort | uniq -c | awk '{print $2,$1}'

(zakładając, że GNU ma lstutaj -Uopcję pomijania sortowania jako optymalizację. Można go bezpiecznie usunąć bez wpływu na funkcjonalność, jeśli nie jest obsługiwana).


mhmh ... później powinienem filtrować każde znalezione rozszerzenie, aby wykonać dla niego akcję?
watchmansky

To zależy od tego, co ostatecznie chcesz zrobić. Czy możesz podać więcej informacji?
groxxda

Mój cel: skrypt przetwarzający każdy plik rozszerzenia (tylko plik obrazu) zmieniający rozmiar na podstawie danych wejściowych użytkownika. Zaczynam od liczby plików jpg, następnego png itp.
watchmansky

rozwiązanie steeldrivers może być bardziej odpowiednie.
groxxda

2
Miałem zarówno JPGi jpgpliki, i chciał go rekurencyjnie więc moje rozwiązanie było napisaćfind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian

11

Rekurencyjnie przegląda pliki i zlicza pasujące rozszerzenia:

$ find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'
   6 tiff
   7 bmp
  26 jpeg
  38 gif
  51 jpg
  54 png

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

3
Nie zapomnij katalogu początkowego z find. Może również pomóc przyszłym czytelnikom tych odpowiedzi, jeśli podasz krótkie wyjaśnienie swojego rozwiązania (na wypadek, gdyby chcieli zmodyfikować go w nieco innym przypadku).
Jeff Schaller

Jak dobrze to rozwiązanie radzi sobie z nazwami ścieżek zawierających spacje? Newlines?
dhag

1
finddomyślnie jest to bieżący katalog, i właśnie z tego korzystam. Nie sądzę, żeby Bóg chciał, aby w nazwach plików były spacje, ale w tym przypadku działa to dobrze. Jeśli masz nowe linie, to zasługujesz na wszystko, co dostajesz. Pomyślałem o wyjaśnieniu, ale zdecydowałem, że odpowiedź będzie zbyt długa, myślę, że liczy się prostota. 99% przypadków w 1% przypadków. Prawdopodobnie jest to zgodne z wersją 7.
Neik,


3

Wszystko, co się wiąże, lsmoże przynieść nieoczekiwane rezultaty ze specjalnymi znakami (spacja i inne symbole). Każdy bashizm (jak tablice) nie jest przenośny. Wszystko, co się wiąże, while readjest zwykle powolne.

Z drugiej strony findjest BARDZO elastyczny (wiele opcji do filtrowania), ma [przynajmniej] dwie składnie, które są bezpieczne dla specjalnych znaków ... i dobrze skaluje się w dużym katalogu.

W tym przykładzie użyłem -inamedopasowania nazwy rozszerzenia zarówno wielkich, jak i małych liter. Ograniczyłem również -maxdepth 1respektowanie pytania „w bieżącym katalogu”. Zamiast zliczać liczbę wierszy, w których nazwy plików mogą zawierać CR / LF, -print0wydrukuje bajt NULL na końcu każdej nazwy pliku ... tak samo | tr -d -c "\000" | wc -ldokładnie zlicza pliki (bajty NULL!).

extensions="jpg png gif"
for ext in $extensions; do
  c=$(find . -maxdepth 1 -iname "*.$ext" -print0 | tr -d -c "\000" | wc -c)
  if [ $c -gt 0 ]; then
    echo "Found $c  *.$ext files"

    find . -maxdepth 1 -iname "*.$ext" -print0 | xargs -0 -r -n1 DOSOMETHINGHERE
    # or #  find . -maxdepth 1 -iname "*.$ext" -exec "ls" "-l" "{}" ";"
  fi
done

PS -print0 | tr -d -c "\000" | wc -cmożna zastąpić -printf "\000" | wc -club nawet -printf '\n' | wc -l.


0

mogę po prostu użyć ls do czegoś takiego prostego IMO

ls -l /opt/ssl/certs/*.pem | wc -l

lub

count=$(ls -l /some/folder/*.jpg | wc -l)

lub

ls *.{mp3,exe,mp4} 2>/dev/null | wc -l

-2

Jeśli jesteś pewien rozszerzenia, możesz przejść z findpodobnymi

find *.jpeg | wc -l

dopóki ktoś nie stworzy touch $'foo\nbar.jpegi nie zostanie policzony dwukrotnie zamiast raz. Lub gorzej, ktoś to robimkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Jeff Schaller
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.