rechercher tous les sous-répertoires d'extrémité dans un arbre

11

étant donné la structure suivante:

oz123@debian:~/ $ tree .
.
├── a
│   ├── a1
│   ├── a2
│   └── a3
├── a1
│   ├── a11
│   ├── a12
│   └── a31
├── b
│   └── b1
│       ├── b11
│       │   └── b21
│       │       └── b31
│       ├── b12
│       └── b3
└── c

16 directories, 0 files

Comment trouver tous les nœuds d'extrémité?

J'ai trouvé les solutions suivantes qui semblent être bonnes, mais je dois prouver qu'il n'y a pas de cas de test qui échouera.

La page d'aide des -linksétats:

Vous pouvez également rechercher des fichiers qui ont un certain nombre de liens, avec '-links'. Les répertoires ont normalement au moins deux liens durs; leur . l'entrée est la deuxième. S'ils ont des sous-répertoires, chacun d'eux a également un lien dur appelé .. vers son répertoire parent. Le . et .. les entrées du répertoire ne sont normalement pas recherchées sauf si elles sont mentionnées sur la ligne de commande find.

solution possible:

oz123@debian:~/ $ find .  -type d  -links 2
./a/a2
./a/a3
./a/a1
./c
./a1/a31
./a1/a11
./a1/a12
./b/b1/b12
./b/b1/b3
./b/b1/b11/b21/b31
  • Quelqu'un peut-il fournir une meilleure solution (sans utiliser de tuyaux et de sed, cela a été performant ...)
  • Cela fonctionnera-t-il sur n'importe quel système de fichiers?
Oz123
la source
3
Vous ne trouverez pas plus performant que l' -links 2astuce. Cela ne fonctionnera pas btrfs.
Stéphane Chazelas

Réponses:

3

En complément de votre propre solution avec -links, je veux simplement ajouter que cela ne fonctionnera pas sur les systèmes de fichiers qui ne suivent pas la convention de lien de répertoire Unix. À partir man findde l'option on, -noleafil s'agit au moins de CD-ROM, de systèmes de fichiers MS-DOS et de points de montage de volume AFS.

Pour référence, cette question a déjà été discutée avec différentes solutions qui sont en effet plus lentes et recourent généralement à la tuyauterie à sed / awk et similaire.

Miroslav Koškár
la source
3

Il y a une option un peu plus évidente -empty:

find . -type d -empty

upd. Ok, vous avez raison, cela ne fonctionnera pas avec les fichiers dans les répertoires.

Voici donc une version non fiable du système de fichiers fixe:

find dtest/ -type d -exec sh -c "if [ \$(find {} -maxdepth 1 -type d | wc -l) -eq 1 ]; then echo {} ; fi" \;
se ruer
la source
2
Si je comprends la question, les répertoires de fin peuvent contenir des fichiers. Cela n'imprimerait pas ces répertoires car ils ne seraient pas "vides" ...
Stefan
@rush, les sous-répertoires peuvent être vides ou non
Oz123
@ Oz123 s'il vous plaît vérifier ma mise à jour, elle devrait être assez rapide, mais un peu plus lente par rapport à votre chemin.
rush
@rush, merci, mais j'ai vraiment besoin d'éviter les tuyaux, ils peuvent ralentir les choses.
Oz123
1

find . -type d -links 2fonctionne sur la plupart des systèmes de fichiers, mais pas sur tous. Je ne pense pas qu'il existe un moyen de savoir autre que de savoir quels types de systèmes de fichiers ont la propriété que les répertoires contiennent un lien vers eux-mêmes. GNU find le détecte dynamiquement (s'il imprime quelque chose sur «Activer automatiquement l'option -noleaf de find», vous savez que votre système de fichiers n'a pas cette propriété). Les types de systèmes de fichiers les plus courants sont corrects, mais pas FAT ou btrfs.

Si vous voulez en être sûr, vous devrez tester chaque répertoire. Une façon de procéder consiste à invoquer à findnouveau pour chaque sous-répertoire.

find . -type d ! -exec sh -c '
   find "$1/." ! -name . -type d -prune | grep -q "^"' sh {} \; -print

(avec GNU find, vous pouvez le remplacer -prunepar -print -quitpour le rendre un peu plus efficace).

Une autre façon consiste à post-traiter la sortie de find. Avec find -depth, un répertoire feuille est un répertoire qui ne suit pas un sous-répertoire de lui-même.

find . -depth -type d -print0 |
awk -v RS='\0' '
    substr(previous, 1, length($0) + 1) != $0 "/"
    { previous = $0 }
'
Gilles 'SO- arrête d'être méchant'
la source
0

Essayez la solution suivante (doit être compatible Linux, Unix et OS X):

find . -type d -execdir sh -c 'test -z "$(find "{}" -mindepth 1 -type d)" && echo $PWD/{}' ';'

C'est une approche similaire à la solution urgente , mais sans aucun tuyau.

Kenorb
la source