Comando UNIX para enumerar carpetas con recuentos de archivos
Pregunta
Deseo obtener una lista de carpetas en el nivel actual (sin incluir sus subcarpetas) y simplemente imprimir el nombre de la carpeta y un recuento del número de archivos en la carpeta (preferiblemente filtrando a * .jpg si es posible).
¿Es esto posible en el shell bash estándar? ls -l
imprime sobre todo menos el recuento de archivos :)
Solución
Se me ocurrió este:
find -maxdepth 1 -type d | while read dir; do
count=$(find "$dir" -maxdepth 1 -iname \*.jpg | wc -l)
echo "$dir ; $count"
done
Descarte el segundo -maxdepth 1
si la búsqueda en los directorios de archivos jpg debe ser recursiva teniendo en cuenta los subdirectorios. Tenga en cuenta que eso solo considera el nombre de los archivos. Puede cambiar el nombre de un archivo, ocultando que es una imagen jpg. En su lugar, puede usar el comando file
para adivinar el contenido (ahora, también busca de forma recursiva):
find -mindepth 1 -maxdepth 1 -type d | while read dir; do
count=$(find "$dir" -type f | xargs file -b --mime-type |
grep 'image/jpeg' | wc -l)
echo "$dir ; $count"
done
Sin embargo, eso es mucho más lento, ya que tiene que leer parte de los archivos y eventualmente interpretar lo que contienen (si tiene suerte, encuentra una identificación mágica al comienzo del archivo). El -mindepth 1
evita que imprima .
(el directorio actual) como otro directorio que busca.
Otros consejos
Encontré esta pregunta después de haber descubierto mi propio script similar. Parece ajustarse a sus condiciones y es muy flexible, así que pensé en agregarlo como respuesta.
Ventajas :
- se puede agrupar a cualquier profundidad (0 para
.
, 1 para subdirectorios de primer nivel, etc.) - imprime una salida bonita
- sin bucle, y solo un comando
find
, por lo que es un poco más rápido en directorios grandes - todavía se puede ajustar para agregar filtros personalizados (profundidad máxima para que no sea recursivo, patrón de nombre de archivo)
Código sin formato:
find -P . -type f | rev | cut -d/ -f2- | rev | \
cut -d/ -f1-2 | cut -d/ -f2- | sort | uniq -c
Envuelto en una función y explicado:
fc() {
# Usage: fc [depth >= 0, default 1]
# 1. List all files, not following symlinks.
# (Add filters like -maxdepth 1 or -iname='*.jpg' here.)
# 2. Cut off filenames in bulk. Reverse and chop to the
# first / (remove filename). Reverse back.
# 3. Cut everything after the specified depth, so that each line
# contains only the relevant directory path
# 4. Cut off the preceeding '.' unless that's all there is.
# 5. Sort and group to unique lines with count.
find -P . -type f \
| rev | cut -d/ -f2- | rev \
| cut -d/ -f1-$((${1:-1}+1)) \
| cut -d/ -f2- \
| sort | uniq -c
}
Produce resultados como este:
$ fc 0
1668 .
$ fc # depth of 1 is default
6 .
3 .ssh
11 Desktop
44 Downloads
1054 Music
550 Pictures
Por supuesto, con el número primero se puede canalizar a sort
:
$ fc | sort
3 .ssh
6 .
11 Desktop
44 Downloads
550 Pictures
1054 Music
el mío es más rápido de escribir desde la línea de comando. :)
¿las otras sugerencias ofrecen alguna ventaja real sobre las siguientes?
find -name '*.jpg' | wc -l # recursive
find -maxdepth 1 -name '*.jpg' | wc -l # current directory only
#!/bin/bash
for dir in `find . -type d | grep -v "\.<*>quot;`; do
echo $dir
ls $dir/*.jpg | wc -l
done;
Puede hacerlo sin comandos externos:
for d in */; do
set -- "$d"*.jpg
printf "%s: %d\n" "${d%/}" "$#"
done
O puede usar awk ( nawk o / usr / xpg4 / bin / awk en Solaris ) :
printf "%s\n" */*jpg |
awk -F\/ 'END {
for (d in _)
print d ":",_[d]
}
{ _[$1]++ }'