Eliminar árboles de directorios vacíos (eliminando tantos directorios como sea posible pero sin archivos)

12

Supongamos que tengo un árbol de directorios como este:

ROOTDIR
    └--SUBDIR1
        └----SUBDIR2
            └----SUBDIR3

Estoy buscando un comando tal que cuando ingreso:

$ [unknown command] ROOTDIR

Se puede eliminar todo el árbol de directorios si no hay un archivo, sino solo directorios dentro del árbol completo . Sin embargo, diga si hay un archivo llamado hello.pdf en SUBDIR1:

ROOTDIR
    └--SUBDIR1
        └--hello.pdf
        └----SUBDIR2
            └----SUBDIR3

Entonces el comando solo debe eliminar SUBDIR2 y más abajo.

gsklee
fuente
Esto parece ser un duplicado de ¿Cómo eliminar todos los directorios vacíos en un subárbol?
David Cary

Respuestas:

11

Alexis está cerca. Lo que debes hacer es esto:

find . -type d -depth -empty -exec rmdir "{}" \;

Primero, profundizará en el árbol de directorios hasta que encuentre el primer directorio vacío, luego bórrelo. De este modo, se vacía el directorio principal, que luego se eliminará, etc. Esto producirá el efecto deseado (lo hago probablemente 10 veces por semana, así que estoy bastante seguro de que es correcto). :-)

Steve Juranich
fuente
¿Por qué es -depthnecesaria la opción? find . -type d -empty -exec rmdir "{}" \;También debería funcionar ... ¿verdad?
Abhishek A
44
Considere si tiene un árbol (solo directorios) foo/bar/baz. A menos que use -depth, intentará eliminar fooprimero, fallar, y terminará foo/bardespués de ejecutarse.
l0b0
1
Posiblemente, la alternativa es utilizar en +lugar de ;eliminar directorios por lotes. Como lo está haciendo en profundidad, los elementos secundarios se eliminarán antes que los padres (posiblemente dependiendo de su versión de rmdir / bash y dependiendo de que rmdir no elimine directorios no vacíos). Esto funciona para mí en bash en cygwin:mkdir -p a/b/c/d ; find a -depth -type d -exec rmdir {} +
idbrii
3
¡Gente, busque la respuesta mucho más sucinta de go2null a continuación! No puedo entender por qué SE da prioridad a las respuestas aceptadas en lugar de las respuestas con la mayoría de los votos positivos al mostrar las respuestas debajo de la pregunta. El OP acepta la mejor respuesta disponible en el momento de su elección, pero más adelante pueden llegar respuestas mucho mejores que la comunidad vota, ¿no? (Por supuesto, esto es algo para meta ...)
jamadagni
Esto no funciona para mi. solo elimina la hoja más profunda (SUBDIR3 en este caso)
Joey Baruch
23
find ROOTDIR -type d -empty -delete

igual que

find ROOTDIR -type d -depth -empty -exec rmdir "{}" \;

pero usa la acción integrada "-delete".

Tenga en cuenta que "-delete" implica "-depth".

go2null
fuente
¡Felicitaciones por la respuesta más sucinta usando el propio borrado incorporado de find! ¡Estoy agregando esto a mis secuencias de comandos locales!
jamadagni
3

Yo intentaría esto:

find ROOTDIR -type d -depth -exec rmdir {} \;
Alexis
fuente
1

Aquí hay algunos requisitos antes de que podamos hacerlo de manera segura:

  1. elimine los subdirectorios primero y luego los directorios de nivel superior, es decir, necesitamos ordenar el listado de directorios o usar rmdir --parents flag
  2. inicie ROOTDIR siempre con / o ./ para evitar sorpresas con archivos que comienzan con -
  3. use la lista de directorios terminada en NUL para trabajar con nombres de directorio con espacios

Así es como lo haría en shell:

find ./ROOTDIR -type d | sort -r | tr '\n' '\000' | xargs -0 rmdir --ignore-fail-on-non-empty

Si no le importan algunos errores redundantes, simplemente puede forzar la eliminación de todos los directorios con los padres y no necesita ordenarlos (no puede ordenar las cadenas terminadas en NUL, lo que agrega la necesidad de tr)

find ./ROOTDIR -type d -print0 | xargs -0 rmdir --ignore-fail-on-non-empty --parents
Puma
fuente
Felicitaciones por la explicación detallada de su respuesta. Probablemente hubiera usado el mismo enfoque, hasta que aprendí sobre las -empty -deleteopciones finden la respuesta de @ go2null.
Davor Cubranic
0
rmdir $(find ROOTDIR -type d | sort -r)
lanzz
fuente
55
Esto no funcionará si alguno de los nombres de directorio contiene espacios en blanco o caracteres globales. Generalmente es una mala idea usar la sustitución de comandos en una lista de nombres de archivos. Es especialmente una mala idea con findporque findtiene una manera de hacer el procesamiento limpiamente: find … -exec.
Gilles 'SO- deja de ser malvado'
Gracias a Gilles por señalar eso. @lanzz, generalmente publicar solo un comando sin explicar lo que hace (y en este caso, las trampas) no es suficiente. Por favor agregue a su respuesta.
n0pe
0

Yo haría esto:

find ROOTDIR -type d | xargs -0 -I {} rmdir {}
chemila
fuente