2009-03-10 13 views
17

Quiero obtener una lista de carpetas en el nivel actual (sin incluir sus subcarpetas) y simplemente imprimir el nombre de la carpeta y un recuento de la cantidad de archivos en la carpeta (preferiblemente filtrar a * .jpg si es posible).Comando UNIX para listar carpetas con conteos de archivos

¿Es esto posible en el shell bash estándar? ls -l impresiones sobre todo, pero el archivo cuentan :)

+2

Para la persona que votó cerca de: Bash es un lenguaje real . – Bernard

Respuesta

21

se me ha ocurrido con éste:

find -maxdepth 1 -type d | while read dir; do 
    count=$(find "$dir" -maxdepth 1 -iname \*.jpg | wc -l) 
    echo "$dir ; $count" 
done 

gota la segunda -maxdepth 1 si la búsqueda dentro de los directorios de archivos jpg debe ser recursivo considerando subdirectorios . Tenga en cuenta que eso solo considera el nombre de los archivos. Podría cambiar el nombre de un archivo, ocultando que se trata de una imagen jpg. Puede utilizar el comando file hacer una conjetura sobre el contenido, en lugar (en la actualidad, también las búsquedas 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, es mucho más lento, ya que tiene que leer una parte de los archivos y, finalmente, interpretar lo contienen (si tiene suerte, encuentra una identificación mágica al comienzo del archivo). El -mindepth 1 impide que imprima . (el directorio actual) como otro directorio que busca.

1
#!/bin/bash 
for dir in `find . -type d | grep -v "\.$"`; do 
echo $dir 
ls $dir/*.jpg | wc -l 
done; 
8

mina es más rápido para escribir desde la línea de comandos. :)

¿las otras sugerencias ofrecen alguna ventaja real sobre lo siguiente?

find -name '*.jpg' | wc -l    # recursive 


find -maxdepth 1 -name '*.jpg' | wc -l # current directory only 
+0

ejemplo: el profesor quiere listas de imágenes jpg de sus alumnos. entonces él pone el comando en/home y quiere listar todos los jpg en esos subdirectores para validar que no contienen algunos *** cosas :) ejemplo de mi anterior profesor de Unix. sabía de lo que estaba hablando: pppls intentó ocultar su pr0n en archivos bin: D –

+0

que solo imprime el número total de archivos, no el número por carpeta. Lo hice ahora de todos modos, siguiendo el comentario anterior. – DisgruntledGoat

+0

@DisgruntledGoat, leí mal su pregunta. Lo siento por eso. Entiendo ahora. – m42

1

Puede hacerlo sin comandos externos:

for d in */; do 
    set -- "$d"*.jpg 
    printf "%s: %d\n" "${d%/}" "$#" 
done 

o puede utilizar awk (nawk o /usr/xpg4/bin/awk en Solaris):

printf "%s\n" */*jpg | 
    awk -F\/ 'END { 
    for (d in _) 
     print d ":",_[d] 
     } 
    { _[$1]++ }' 
9

He encontrado esta pregunta afte r Ya había descubierto mi propio script similar. Parece ajustarse a tus condiciones y es muy flexible, así que pensé en agregarlo como respuesta.

Ventajas:

  • se pueden agrupar a cualquier profundidad (0 para ., 1 para los subdirectorios de primer nivel, etc.)
  • salida se imprime bastante
  • ningún bucle, y sólo una find de mando, así que es un poco más rápido en grandes directorios
  • todavía puede ser sintonizado para añadir filtros personalizados (maxdepth para que sea no recursivo, el nombre del archivo de patrones)

código prima:

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 explicó:

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 una salida como esta:

$ fc 0 
1668 . 

$ fC# depth of 1 is default 
    6 . 
    3 .ssh 
    11 Desktop 
    44 Downloads 
1054 Music 
550 Pictures 

Por supuesto, con el primer número que se puede canalizar a sort:

$ fc | sort 
    3 .ssh 
    6 . 
    11 Desktop 
    44 Downloads 
550 Pictures 
1054 Music 
+0

En Solaris no hay 'rev 'disponible. Puede usar 'perl' en su lugar como solución universal: ' encontrar -P. -type f | perl -lpe '$ _ = reverse' | corte -d/-f2- | perl -lpe '$ _ = reverse' | corte -d/-f1-2 | corte -d/-f2- | ordenar | uniq -c' –

Cuestiones relacionadas