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.