Conta i file in una directory per estensione


15

Ai fini del test, vorrei contare il numero di file di immagini all'interno di una directory, separando ciascun tipo di file di immagine in base all'estensione del file (jpg = "sì". Questo perché in seguito sarà utile per un altro script che eseguirà un'azione su ciascuna estensione di file). Posso usare qualcosa di simile al seguente solo per file JPEG?

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

Considerando le estensioni dei file jpg, png, bmp, raw e altri, dovrei usare un whileciclo per fare questo?

Risposte:


14

Suggerirei un approccio diverso, evitando i possibili problemi di divisione delle parole 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

È possibile eseguire il loop filessull'array con qualsiasi altro comando che si desidera eseguire sui file di ogni particolare estensione.


Più facilmente - o per shell che non forniscono esplicitamente array - è possibile riutilizzare l'array di parametri posizionali della shell, ad es.

set -- *."$ext"

e quindi sostituire ${#files[@]}e ${files[@]}con $#e"$@"


23

Il mio approccio sarebbe:

  1. Elenca tutti i file nella directory
  2. Estrai la loro estensione
  3. Ordina il risultato
  4. Conta le occorrenze di ogni estensione

In un certo senso (l'ultima awkchiamata è puramente per la formattazione):

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

(assumendo lsqui GNU per l' -Uopzione di saltare l'ordinamento come ottimizzazione. Può essere rimosso in sicurezza senza influire sulla funzionalità se non supportato).


mhmh ... dopo dovrei filtrare ogni estensione trovata per fare un'azione per essa?
watchmansky,

Dipende da cosa vuoi fare alla fine. Puoi dare maggiori informazioni?
groxxda,

Il mio obiettivo: uno script che elabora ciascun file di estensione (solo file di immagine) modificando la dimensione dai dati dell'utente di input. Quindi, parto da quanti file jpg ci sono, prossimo png, ecc.
watchmansky

La soluzione steeldrivers potrebbe essere più appropriata allora.
groxxda,

2
Ho avuto entrambi JPGe jpgfile, e volevo ricorsivamente così la mia soluzione era quella di scriverefind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian

11

Questo attraversa ricorsivamente i file e conta le estensioni che corrispondono:

$ 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
Non dimenticare una directory iniziale con find. Inoltre, può aiutare i futuri lettori di queste risposte se fornisci una breve spiegazione della tua soluzione (nel caso in cui vorrebbero modificarla per un caso leggermente diverso).
Jeff Schaller

In che misura questa soluzione gestisce i nomi dei percorsi contenenti spazi? A capo?
Dhag,

1
findper impostazione predefinita, la directory corrente, che è come la uso. Non penso che Dio abbia voluto che i nomi dei file contenessero degli spazi, ma in questo caso funziona bene. Se hai newline, ti meriti tutto ciò che ottieni. Ho pensato a una spiegazione, ma ho deciso che avrebbe reso la risposta troppo lunga, penso che la semplicità sia ciò che conta. Il 99% dei casi nell'1% delle volte. Questa è probabilmente la versione 7 compatibile.
Neik,

3

Forse può essere più breve

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

3

lsÈ probabile che tutto ciò che comporta produca risultati inaspettati con caratteri speciali (spazio e altri simboli). Qualsiasi bashismo (come gli array) non è portatile. Tutto ciò che coinvolge while readè generalmente lento.

D'altra parte, findè MOLTO flessibile (molte opzioni per filtrare), ha [almeno] due sintassi che non sono sicure per caratteri speciali ... e si adatta bene su directory di grandi dimensioni.

Per questo esempio, ho usato -inameper abbinare sia il nome di estensione maiuscolo che minuscolo. Ho anche limitato il -maxdepth 1per rispettare la tua domanda "nella directory corrente". Invece di contare il numero di righe, dove i nomi dei file potrebbero includere CR / LF, -print0stamperà un byte NULL alla fine di ogni nome file ... quindi | tr -d -c "\000" | wc -lconta accuratamente i file (byte 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 -cpuò essere sostituito con -printf "\000" | wc -co anche -printf '\n' | wc -l.


0

posso semplicemente usare ls per qualcosa di questo semplice IMO

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

o

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

o

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

-2

Se sei sicuro dell'estensione, puoi scegliere findlike

find *.jpeg | wc -l

fino a quando qualcuno crea touch $'foo\nbar.jpege viene conteggiato due volte anziché una volta. O peggio, qualcuno lo famkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Jeff Schaller
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.