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?

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"$@"


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


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

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

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;

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.


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

-2

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

find *.jpeg | wc -l

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.