Rechercher des répertoires contenant un certain nombre de fichiers

13

J'espérais pouvoir le faire avec la findcommande mais je ne vois aucun test dans le manuel pour faire ce que je veux. Je voudrais pouvoir trouver dans le répertoire de travail tous les répertoires contenant moins que, plus que ou exactement le nombre que je spécifie.

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

Mais hélas, il n'y a pas une telle option.

Paul Ruane
la source
essayez quelque chose comme "ls -al | wc -l | grep"
Vanadis

Réponses:

16

Vous pouvez essayer ceci, pour obtenir les noms des sous-répertoires et le nombre de fichiers / répertoires qu'ils contiennent:

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

Si vous souhaitez faire de même pour tous les sous-répertoires (recherche récursive), utilisez plutôt ceci:

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

Pour sélectionner les répertoires contenant exactement 10 fichiers:

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

10 ou plus:

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

10 ou moins:

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

Si vous souhaitez conserver uniquement le nom du répertoire (par exemple, si vous souhaitez le rediriger vers un autre processus en aval comme l'a suggéré @evilsoup), vous pouvez utiliser ceci:

find . -maxdepth 1 -type d -exec bash -c "echo -ne '{}\t'; ls '{}' | wc -l" \; | 
 awk -F"\t" '$NF<=10{print $1}'
terdon
la source
1
Je pense qu'il pourrait être utile d'inclure la commande awk pour couper le nombre de fichiers (c'est-à-dire la dernière colonne délimitée par des espaces), au cas où le questionneur voudrait diriger la sortie vers autre chose.
evilsoup
1
@evilsoup bonne idée, c'est fait.
terdon
Pour prendre en charge les espaces blancs et les caractères spéciaux dans les noms de répertoire; essayez d'inverser l'utilisation des guillemets simples et doubles en tant que tels:find . -type d -exec bash -c 'echo -ne "{} "; ls "{}" | wc -l' \; | awk '$NF<=10'
Håvard Geithus
3

Pour répertorier les sous-répertoires immédiats contenant exactement les $NUM fichiers.

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}'

Pour répertorier les sous-répertoires immédiats contenant des$NUM fichiers supérieurs à .

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}'

Pour répertorier les sous-répertoires immédiats contenant moins de $NUMfichiers.

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}'

Les éléments sont terminés par un caractère nul \0, donc les noms de fichiers qui contiennent des sauts de ligne ou d'autres types d'espaces blancs seront interprétés correctement. Le %himprime chaque fichier dirname. awkutilise ensuite un tableau pour compter le nombre de fois qu'il rencontre chaque répertoire, en l'imprimant si les conditions sont remplies.

Veuillez noter qu'aucune des commandes susmentionnées n'affichera les répertoires contenant zéro fichier. Notez également que par fichier, je fais référence aux fichiers normaux, pas aux liens, répertoires, sockets, blocs, canaux nommés, etc.

J'ai essayé de le faire aussi simplement que possible. Si vous souhaitez rechercher des sous-répertoires récursifs ou les fichiers qu'ils contiennent, une commande modifiée est requise. Il y a trop de possibilités pour tous les énumérer.

Six
la source
2

Essaye ça:

[`trouver. | wc -l` -eq 10] && echo "Trouvé"

[`trouver. | wc -l` -gt 10] && echo "Trouvé"

[`trouver. | wc -l` -lt 10] && echo "Trouvé"

Dans ces exemples, vous pouvez vérifier si le répertoire CURRENT contient exactement 10, plus de 10 et moins de 10 fichiers / répertoires. Si vous devez vérifier plusieurs répertoires, utilisez simplement loop.

septembre
la source
Votre solution compte également le répertoire actuel ( .), que vous souhaiterez peut-être modifier en conséquence.
terdon
J'aime la poussée de cette réponse (parce que je suis un glouton pour faire des choses dans le shell), mais il vaut mieux utiliser wc -l < <(printf %s\\n ./*)ou printf %s\\n ./* | wc -là l'intérieur du test, pour éviter un findappel inutile . Cela évitera également le problème que @terdon a noté, d'inclure .dans le résultat. Cependant, cela poserait également le problème d'ignorer les fichiers commençant par un .; Je résoudrais cela avec shopt -s dotglob(pour que les globes correspondent aux fichiers commençant par un ., mais pas .ou ..).
evilsoup
@terdon Ce n'est pas important. Ce n'est pas une solution finale, juste un exemple, une idée. Vous pouvez -1, ou changer 10 en 11 dans la version finale.
septembre
Je sais, et l'idée est bonne, c'est pourquoi j'ai fait cette suggestion.
terdon
@ terdon. Je vous remercie. Il peut y avoir de nombreuses exigences différentes, telles que: compter uniquement les fichiers mais pas les répertoires, les liens ou les liens matériels. Comptez ou non les fichiers dans les sous-répertoires. Comptez les fichiers cachés (comme .bashrc) ... ... pour que votre expression puisse être très longue. :)
septembre