Zählen Sie die Dateien in einem Verzeichnis nach Erweiterung

15

Zu Testzwecken möchte ich zählen, wie viele Bilddateien sich in einem Verzeichnis befinden, wobei jeder Bilddateityp durch die Dateierweiterung getrennt wird (jpg = "yes". Dies ist nützlich, da es später für ein anderes Skript nützlich ist, das eine Aktion ausführt auf jeder Dateierweiterung). Kann ich für JPEG-Dateien Folgendes verwenden?

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

Sollte ich unter Berücksichtigung der Dateierweiterungen jpg, png, bmp, raw und anderer einen whileZyklus verwenden, um dies zu tun?

Wachmann
quelle

Antworten:

14

Ich würde eine andere Herangehensweise vorschlagen, um die möglichen Worttrennungsprobleme von zu vermeiden 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

Sie können das filesArray mit allen anderen Befehlen durchlaufen, die Sie für die Dateien der jeweiligen Erweiterung ausführen möchten.


Portabler - oder für Shells, die keine expliziten Arrays bereitstellen - können Sie das Positionsparameter-Array der Shell wiederverwenden, z

set -- *."$ext"

und dann ersetzen ${#files[@]}und ${files[@]}mit $#und"$@"

Stahlfahrer
quelle
23

Mein Ansatz wäre:

  1. Listen Sie alle Dateien im Verzeichnis auf
  2. Extrahieren Sie ihre Erweiterung
  3. Sortieren Sie das Ergebnis
  4. Zählen Sie die Vorkommen jeder Erweiterung

So ähnlich (letzter awkAufruf dient nur zur Formatierung):

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

(Angenommen, GNU lshier für die -UOption, das Sortieren als Optimierung zu überspringen. Es kann sicher entfernt werden, ohne die Funktionalität zu beeinträchtigen, wenn es nicht unterstützt wird.)

groxxda
quelle
mhmh ... soll ich später jede gefundene Nebenstelle filtern, um eine Aktion dafür durchzuführen?
Watchmansky
Es hängt davon ab, was Sie am Ende tun möchten. Können Sie weitere Informationen geben?
Groxxda
Mein Ziel: Ein Skript, das jede Erweiterungsdatei (nur Bilddatei) verarbeitet und die Größe anhand der eingegebenen Benutzerdaten ändert. Also, ich beginne mit der Anzahl der JPG-Dateien, dem nächsten PNG usw.
watchmansky
Eine Lösung mit Stahlfahrern ist dann möglicherweise besser geeignet.
Groxxda
2
Ich hatte beides JPGund jpgDateien und wollte es rekursiv, also bestand meine Lösung darin, zu schreibenfind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian,
11

Dies durchläuft rekursiv Dateien und zählt Erweiterungen, die übereinstimmen:

$ 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
Kit
quelle
5
find -type f | sed -e 's/.*\.//' | sort | uniq -c
Neik
quelle
3
Vergessen Sie nicht ein Startverzeichnis mit find. Es kann auch zukünftigen Lesern dieser Antworten helfen, wenn Sie eine kurze Erläuterung Ihrer Lösung geben (falls sie diese für einen etwas anderen Fall ändern möchten).
Jeff Schaller
Wie gut geht diese Lösung mit Pfadnamen um, die Leerzeichen enthalten? Newlines?
Dhag
1
findStandardmäßig wird das aktuelle Verzeichnis verwendet, wie ich es benutze. Ich glaube nicht, dass Gott beabsichtigt hat, dass Dateinamen Leerzeichen enthalten, aber das funktioniert in diesem Fall. Wenn Sie Zeilenumbrüche haben, dann haben Sie alles verdient, was Sie bekommen. Ich dachte über eine Erklärung nach, entschied aber, dass die Antwort dadurch zu lang wird. Ich denke, Einfachheit ist das, worauf es ankommt. 99% der Fälle in 1% der Zeit. Dies ist wahrscheinlich Version 7 kompatibel.
Neik
3

Vielleicht kann es kürzer werden

exts=( *.jpg *.png *.gif ); printf "There are ${#exts[@]}" extensions;
Valentin Bajrami
quelle
3

Alles, was damit zu tun hat, lsführt wahrscheinlich zu unerwarteten Ergebnissen mit Sonderzeichen (Leerzeichen und andere Symbole). Jeder Bashismus (wie Arrays) ist nicht portierbar. Alles was damit zu tun hat, while readist normalerweise langsam.

Auf der anderen Seite findist es SEHR flexibel (viele Filteroptionen), es hat [mindestens] zwei Syntax, die für spezielle Zeichen ausfallsicher sind ... und es lässt sich gut in großen Verzeichnissen skalieren.

In diesem Beispiel habe ich -inameGroß- und Kleinbuchstaben für Erweiterungsnamen verwendet. Ich habe mich auch darauf beschränkt -maxdepth 1, Ihre Frage "im aktuellen Verzeichnis" zu respektieren. Anstatt die Anzahl der Zeilen zu zählen, in denen Dateinamen CR / LF enthalten könnten, -print0wird am Ende jedes Dateinamens ein NULL-Byte ausgegeben ... | tr -d -c "\000" | wc -lgenaues Zählen der Dateien (NULL-Bytes!).

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 -ckann mit -printf "\000" | wc -coder sogar ersetzt werden -printf '\n' | wc -l.

Franklin Piat
quelle
0

kann ls nur für etwas verwenden, das so einfach ist wie IMO

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

oder

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

oder

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

Wenn Sie sich der Erweiterung sicher sind, können Sie findgerne mitgehen

find *.jpeg | wc -l
Nithish JV
quelle
bis jemand schafft touch $'foo\nbar.jpegund es wird zweimal statt einmal gezählt. Oder schlimmer, jemand tut esmkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Jeff Schaller