encontrar todos los subdirectorios finales en un árbol

11

dada la siguiente estructura:

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

16 directories, 0 files

¿Cómo encuentro todos los nodos finales?

Encontré las siguientes soluciones que parecen ser buenas, pero tengo que demostrar que no hay un caso de prueba que falle.

La página de ayuda de los -linksestados:

También puede buscar archivos que tengan un cierto número de enlaces, con 'enlaces'. Los directorios normalmente tienen al menos dos enlaces duros; su . La entrada es la segunda. Si tienen subdirectorios, cada uno de ellos también tiene un enlace rígido llamado .. a su directorio padre. Los . y .. las entradas de directorio normalmente no se buscan a menos que se mencionen en la línea de comando de búsqueda.

solución posible:

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
  • ¿Alguien puede proporcionar una mejor solución (sin usar tuberías y sed, esto ha sido eficaz ...)
  • ¿Funcionará en cualquier sistema de archivos?
Oz123
fuente
3
No encontrarás más rendimiento que el -links 2truco. No funcionará btrfs.
Stéphane Chazelas

Respuestas:

3

Como una adición a su propia solución -links, solo quiero agregar que no funcionará en sistemas de archivos que no sigan la convención de enlace de directorio de Unix. Desde la man findopción, -noleafestos son al menos CD-ROM, sistemas de archivos MS-DOS y puntos de montaje de volumen AFS.

Como referencia, esta pregunta ya se discutió con diferentes soluciones que de hecho son más lentas y generalmente recurren a tuberías a sed / awk y similares.

Miroslav Koškár
fuente
3

Hay una opción un poco más obvia -empty:

find . -type d -empty

upd Ok, tienes razón de esta manera no funcionará con archivos en directorios.

Así que aquí está una versión no confiable del sistema de archivos fijo:

find dtest/ -type d -exec sh -c "if [ \$(find {} -maxdepth 1 -type d | wc -l) -eq 1 ]; then echo {} ; fi" \;
prisa
fuente
2
Si entiendo la pregunta, los directorios finales pueden contener archivos. Esto no imprimiría esos directorios ya que no estarían "vacíos" ...
Stefan
@rush, los subdirs pueden estar vacíos o no
Oz123
@ Oz123, compruebe mi actualización, debe ser lo suficientemente rápido, pero un poco más lento en comparación con su camino.
prisa el
@ Rush, gracias, pero realmente necesito evitar las tuberías, pueden hacer las cosas más lentas.
Oz123
1

find . -type d -links 2funciona en la mayoría de los sistemas de archivos, pero no en todos. No creo que haya una manera de saber más que saber qué tipos de sistemas de archivos tienen la propiedad de que los directorios contienen un enlace a ellos mismos. GNU find detecta esto dinámicamente (si imprime algo sobre "Activar automáticamente la opción find -noleaf", sabrá que su sistema de archivos no tiene esta propiedad). Los tipos de sistema de archivos más comunes están bien, pero no FAT o btrfs.

Si quiere estar seguro, deberá probar cada directorio. Una forma de hacerlo es invocar findnuevamente para cada subdirectorio.

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

(con GNU find, se puede reemplazar -prunecon -print -quitpara que sea un poco más eficiente).

Otra forma es postprocesar la salida de find. Con find -depth, un directorio hoja es uno que no sigue un subdirectorio de sí mismo.

find . -depth -type d -print0 |
awk -v RS='\0' '
    substr(previous, 1, length($0) + 1) != $0 "/"
    { previous = $0 }
'
Gilles 'SO- deja de ser malvado'
fuente
0

Pruebe la siguiente solución (debe ser compatible con Linux, Unix y OS X):

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

Es un enfoque similar a la solución rápida , pero sin tuberías.

kenorb
fuente