Encuentra directorios que contengan una cierta cantidad de archivos

13

Esperaba poder hacer esto con el findcomando, pero no veo ninguna prueba en el manual para hacer lo que quiero. Me gustaría poder encontrar cualquier directorio en el directorio de trabajo que contenga menos que, más que o exactamente el recuento que especifico.

find . -filecount +10 # any directory with more than 10 entries
find . -filecount 20 # any directory with exactly 20 entries

Pero, por desgracia, no existe tal opción.

Paul Ruane
fuente
pruebe algo como "ls -al | wc -l | grep"
Vanadis

Respuestas:

16

Puede intentar esto para obtener los nombres de los subdirectorios y la cantidad de archivos / directorios que contienen:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \;

Si desea hacer lo mismo para todos los subdirectorios (búsqueda recursiva) use esto en su lugar:

find . -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \;

Para seleccionar aquellos directorios que tienen exactamente 10 archivos:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
  awk '$NF==10'

10 o más:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
 awk '$NF>=10'

10 o menos:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{} '; ls '{}' | wc -l" \; | 
 awk '$NF<=10'

Si desea conservar solo el nombre del directorio (por ejemplo, si desea canalizarlo a otro proceso en sentido descendente, como sugiere @evilsoup), puede usar esto:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{}\t'; ls '{}' | wc -l" \; | 
 awk -F"\t" '$NF<=10{print $1}'
terdon
fuente
1
Creo que podría ser útil incluir el comando awk para cortar el recuento de archivos (es decir, la última columna delimitada por espacios en blanco), en caso de que el interlocutor quiera canalizar la salida a otra cosa.
evilsoup
1
@evilsoup buena idea, hecho.
terdon
Para admitir espacios en blanco y caracteres especiales en los nombres de directorio; intente revertir el uso de comillas simples y dobles como tales:find . -type d -exec bash -c 'echo -ne "{} "; ls "{}" | wc -l' \; | awk '$NF<=10'
Håvard Geithus el
3

Para enumerar subdirectorios inmediatos que contienen exactamente $NUM archivos.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]==num) printf "%s\n", line}'

Para enumerar subdirectorios inmediatos que contienen archivos mayores que $NUM.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]>num) printf "%s\n", line}'

Para enumerar subdirectorios inmediatos que contienen menos de $NUMarchivos.

find -maxdepth 2 -mindepth 2 -type f -printf '%h\0' | awk -v num="$NUM" 'BEGIN{RS="\0"} {array[$0]++} END{for (line in array) if (array[line]<num) printf "%s\n", line}'

Los elementos terminan con un carácter nulo \0, por lo que los nombres de archivo que contienen líneas nuevas u otros tipos de espacios en blanco se interpretarán correctamente. Las %himpresiones de cada archivo dirname. awkluego usa una matriz para contar cuántas veces encuentra cada directorio, imprimiéndolo si se cumplen las condiciones.

Tenga en cuenta que ninguno de los comandos mencionados mostrará directorios que contengan cero archivos. También tenga en cuenta que por archivo me refiero a archivos normales, no a enlaces, directorios, tomas, bloques, tuberías con nombre, etc.

He tratado de hacer esto de la forma más simple posible. Si desea encontrar subdirectorios recursivos o los archivos que contiene, se requiere un comando modificado. Hay demasiadas posibilidades para enumerarlos a todos.

Seis
fuente
2

Prueba esto:

[`encontrar. El | wc -l` -eq 10] && echo "Encontrado"

[`encontrar. El | wc -l` -gt 10] && echo "Encontrado"

[`encontrar. El | wc -l` -lt 10] && echo "Encontrado"

En estos ejemplos, puede verificar si el directorio ACTUAL contiene exactamente 10, más de 10 y menos de 10 archivos / directorios. Si necesita verificar un montón de directorios, simplemente use loop.

septiembre
fuente
Su solución también cuenta el directorio actual ( .), es posible que desee modificar en consecuencia.
terdon
Me gusta el empuje de esta respuesta (porque soy un glotón para hacer cosas en la cáscara), pero sería mejor usar wc -l < <(printf %s\\n ./*)o printf %s\\n ./* | wc -ldentro de la prueba, para evitar una findllamada innecesaria . Esto también evitará el problema que @terdon notó, de incluir .en el resultado. Sin embargo, también se encontraría con el problema de ignorar los archivos que comienzan con a .; Me gustaría resolver esto con shopt -s dotglob(para hacer pegotes coinciden con los archivos que comienzan con una ., pero no .o ..).
evilsoup
@terdon No es importante. No es la solución final, solo ejemplo, idea. Puede -1, o cambiar 10 a 11 en la versión final.
septiembre
Lo sé, y la idea es buena, por eso hice la sugerencia.
terdon
@ terdon. Gracias. Puede haber muchos requisitos diferentes, como: contar solo archivos pero no directorios, enlaces o enlaces duros. Cuente o no archivos en subdirectorios. Cuente archivos ocultos (como .bashrc) ... ... para que su expresión pueda ser muuuuy muuuy larga. :)
Septiembre