Quiero eliminar recursivamente todos los archivos a los que no se accede desde hace un tiempo en la carpeta a, excepto todos los archivos en la subcarpeta b.
find a \( -name b -prune \) -o -type f -delete
Sin embargo, recibo un mensaje de error:
find: la acción -delete se activa automáticamente -depth, pero -prune no hace nada cuando -depth está vigente. Si desea continuar de todos modos, use explícitamente la opción -depth.
Agregar -depthhace bque se incluyan todos los archivos , lo que no debe suceder.
¿Alguien sabe una forma segura de hacer que esto funcione?

aexceptoa/b?cd a && ls -d !(b/*)funcionar? (Para hacerlo, solo enrm -rlugar dels -d).a(excepto los archivos debajoa/b).-rrm. Parece que lo que estás preguntando es respondido con bastante facilidad usando el globbing extendido de bash, y luego lo que hagas con el resultado del globbing depende de ti.Respuestas:
TL; DR: la mejor manera es usar en
-exec rmlugar de-delete.Explicación:
¿Por qué encuentra queja cuando intentas usar
-deletecon-prune?Respuesta corta: porque
-deleteimplica-depthy-depthhace-pruneineficaz.Antes de llegar a la respuesta larga, primero observe el comportamiento de encontrar con y sin
-depth:No hay garantía sobre el pedido en un solo directorio. Pero hay una garantía de que un directorio se procesa antes de su contenido. Nota
foo/antesfoo/*yfoo/barantes de cualquierafoo/bar/*.Esto se puede revertir con
-depth.Tenga en cuenta que ahora todos
foo/*aparecen antesfoo/. Lo mismo confoo/bar.Respuesta más larga:
-pruneevita que find descienda a un directorio. En otras palabras,-pruneomite el contenido del directorio. En su caso,-name b -pruneevita que find descienda a cualquier directorio con el nombreb.-depthhace que find procese el contenido de un directorio antes que el directorio mismo. Eso significa que para cuando find procesa la entrada del directorio,bsu contenido ya ha sido procesado. Por-prunelo tanto, es ineficaz con-depthefecto.-deleteimplica-depthpara que pueda eliminar primero los archivos y luego el directorio vacío.-deletese niega a eliminar directorios no vacíos. Supongo que sería posible agregar una opción para forzar la-deleteeliminación de directorios no vacíos y / o para evitar-deleteque esto implique-depth. Pero esa es otra historia.Hay otra forma de lograr lo que quieres:
Esto puede o no ser más fácil de recordar.
Este comando aún desciende al directorio
by procesa cada archivo solo para-notrechazarlos. Esto puede ser un problema de rendimiento si el directoriobes enorme.-pathfunciona de manera diferente-name.-namesolo coincide con el nombre (del archivo o directorio) mientras-pathcoincide con la ruta completa. Por ejemplo, observar el camino/home/lesmana/foo/bar.-name -barcoincidirá porque el nombre esbar.-path "*/foo*"coincidirá porque la cadena/fooestá en la ruta.-pathtiene algunas complejidades que debes entender antes de usarlo. Lea la página de manual defindpara más detalles.Tenga en cuenta que esto no es 100% infalible. Hay posibilidades de "falsos positivos". La forma en que el comando se escribe arriba omitirá cualquier archivo que tenga algún directorio padre cuyo nombre comience con
b(positivo). Pero también omitirá cualquier archivo cuyo nombre comiencebindependientemente de la posición en el árbol (falso positivo). Esto se puede solucionar escribiendo una mejor expresión que"*/b*". Eso se deja como ejercicio para el lector.Supongo que usaste
aybcomo marcadores de posición y los nombres reales son más comoallosaurusybrachiosaurus. Si lo colocabrachiosaurusen su lugarb, la cantidad de falsos positivos se reducirá drásticamente.Al menos los falsos positivos no se eliminarán, por lo que no será tan trágico. Además, puede verificar si hay falsos positivos ejecutando primero el comando sin
-delete(pero recuerde colocar el implícito-depth) y examinar la salida.fuente
-not -pathfue justo la cosa! Gracias por una generosa explicación!-not -pathfunciona mientras-pruneque no es útil. ¿Por qué puede-not -pathcoexistir con-depth?Solo use en
rmlugar de-delete:fuente
rmfunciona ydeleteno funciona?rmno tiene ese problema. Pero, independientemente, la elaboración sería algo bueno.-deleteimplica-depth, que obviamente no puede funcionar-prune.-pathfunciona, pero no dejafindde descender en directorios que no necesita explorar.Las respuestas y explicaciones anteriores fueron muy útiles.
Utilizo las soluciones de "-exec rm {} +" o "-not -path ... -delete ', pero pueden ser mucho más lentas que" find ... -delete ". He visto" find ... -delete "ejecutar 5 veces más rápido que" -exec rm {} + "en directorios profundos en un sistema de archivos NFS.
La solución '-not path "tiene la sobrecarga obvia de mirar todos los archivos en los directorios excluidos y debajo.
El "find .. -exec rm {} +" llama a rm que llama al sistema:
El "find -delete" hace llamadas al sistema:
Entonces, el comando "-exec rm {} +" rm realiza la ruta completa a la búsqueda de inodo dos veces por archivo, pero "find -delete" hace una estadística y desvincula el nombre del archivo en el directorio actual. Esa es una gran victoria cuando está eliminando muchos archivos en un directorio.
(modo de quejas activado (lo siento))
Parece que el diseño de la interacción entre -depth, -delete y -prune elimina innecesariamente la forma más eficiente de realizar la acción común "eliminar archivos excepto aquellos en directorios -prune"
La combinación de "-type f -delete" debería poder ejecutarse sin -depth ya que no está tratando de eliminar directorios. Alternativamente, si "find" tenía una acción "-deletefile" que dice que no elimine directorios, no sería necesario implicar -depth.
Las órdenes xargs o find -exec para el comando rm podrían acelerarse si rm tuviera la opción de ordenar nombres de archivos, abrir directorios y hacer unlinkat (dir_fd, filename) en lugar de desvincular las rutas completas. Ya hace el unlinkat (dir_fd, filename) cuando recurre a través de directorios con la opción -r.
(modo gemido apagado)
fuente