Contar archivos en un directorio por extensión

15

Con el fin de probar, me gustaría contar cuántos archivos de imágenes hay dentro de un directorio, separando cada tipo de archivo de imagen por extensión de archivo (jpg = "yes". Esto porque más tarde será útil para otro script que ejecutará una acción en cada extensión de archivo). ¿Puedo usar algo como lo siguiente solo para archivos JPEG?

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

Teniendo en cuenta las extensiones de archivo jpg, png, bmp, raw y otras, ¿debería usar un whileciclo para hacer esto?

watchmansky
fuente

Respuestas:

14

Sugeriría un enfoque diferente, evitando los posibles problemas de división de palabras de 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

Puede recorrer la filesmatriz con cualquier otro comando que desee ejecutar en los archivos de cada extensión en particular.


De forma más portátil, o para shells que no proporcionan arrays explícitamente, podría reutilizar el array de parámetros posicionales del shell, es decir

set -- *."$ext"

y luego reemplazar ${#files[@]}y ${files[@]}con $#y"$@"

conductor de acero
fuente
23

Mi enfoque sería:

  1. Listar todos los archivos en el directorio
  2. Extraer su extensión
  3. Ordenar el resultado
  4. Cuenta las ocurrencias de cada extensión

Algo así (la última awkllamada es solo para formatear):

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

(suponiendo GNU lsaquí para la -Uopción de omitir la clasificación como una optimización. Se puede eliminar de forma segura sin afectar la funcionalidad si no es compatible).

groxxda
fuente
mhmh ... ¿más tarde debería filtrar cada extensión encontrada para hacer una acción?
watchmansky
Depende de lo que quieras hacer al final. ¿Puedes darme mas información?
groxxda
Mi objetivo: un script que procese cada archivo de extensión (solo archivo de imagen) cambiando el tamaño de los datos de entrada del usuario. Entonces, empiezo a partir de cuántos archivos jpg hay, el próximo png, etc.
watchmansky
La solución de SteelDrivers puede ser más apropiada entonces.
groxxda
2
Tenía ambos JPGy jpgarchivos, y lo quería recursivamente, así que mi solución fue escribirfind . -type f | awk -F . '{print tolower($NF)}' | sort | uniq -c | awk '{print $2,":",$1}'
Kristian,
11

Esto atraviesa recursivamente archivos y cuenta extensiones que coinciden:

$ 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
Equipo
fuente
6
find -type f | sed -e 's/.*\.//' | sort | uniq -c
Neik
fuente
3
No olvides un directorio inicial con find. Además, puede ayudar a los futuros lectores de estas respuestas si brinda una breve explicación de su solución (en caso de que deseen modificarla por un caso ligeramente diferente).
Jeff Schaller
¿Qué tan bien trata esta solución con los nombres de ruta que contienen espacios? Newlines?
dhag
1
findPor defecto es el directorio actual, que es cómo uso esto. No creo que Dios pretendiera que los nombres de los archivos tuvieran espacios, pero esto funciona bien para ese caso. Si tienes nuevas líneas, entonces mereces todo lo que obtienes. Pensé en una explicación, pero decidí que la respuesta sería demasiado larga, creo que la simplicidad es lo que importa. 99% de los casos en 1% del tiempo. Esta es probablemente la versión 7 compatible.
Neik
3

Tal vez puede acortarse

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

Cualquier cosa que involucre ls es probable que produzca resultados inesperados con caracteres especiales (espacio y otros símbolos). Cualquier bashismo (como las matrices) no es portátil. Cualquier cosa que implique while reades generalmente lenta.

Por otra parte, find es MUY flexible (muchas opciones para filtrar), tiene [al menos] dos sintaxis que son a prueba de fallas para caracteres especiales ... y se escala bien en directorios grandes.

Para este ejemplo, solía -inamecoincidir con el nombre de la extensión en mayúsculas y minúsculas. También he restringido el -maxdepth 1para respetar su pregunta "en el directorio actual". En lugar de contar el número de líneas, donde los nombres de archivo podrían incluir CR / LF, -print0se imprimirá un byte NULL al final de cada nombre de archivo ... así que | tr -d -c "\000" | wc -lse cuentan los archivos con precisión (¡bytes 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 -cpuede ser reemplazado con -printf "\000" | wc -co incluso -printf '\n' | wc -l.

Franklin Piat
fuente
0

puede usar ls para algo tan simple como OMI

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
Mike Q
fuente
-2

Si está seguro de la extensión, se puede ir con findigual

find *.jpeg | wc -l
Nithish JV
fuente
hasta que alguien crea touch $'foo\nbar.jpegy se cuenta dos veces en lugar de una vez. O peor, alguien lo hacemkdir directory.jpeg; touch directory.jpeg/{1..100}.txt
Jeff Schaller