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 -depth
hace b
que se incluyan todos los archivos , lo que no debe suceder.
¿Alguien sabe una forma segura de hacer que esto funcione?
a
exceptoa/b
?cd a && ls -d !(b/*)
funcionar? (Para hacerlo, solo enrm -r
lugar dels -d
).a
(excepto los archivos debajoa/b
).-r
rm. 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 rm
lugar de-delete
.Explicación:
¿Por qué encuentra queja cuando intentas usar
-delete
con-prune
?Respuesta corta: porque
-delete
implica-depth
y-depth
hace-prune
ineficaz.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/bar
antes 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:
-prune
evita que find descienda a un directorio. En otras palabras,-prune
omite el contenido del directorio. En su caso,-name b -prune
evita que find descienda a cualquier directorio con el nombreb
.-depth
hace que find procese el contenido de un directorio antes que el directorio mismo. Eso significa que para cuando find procesa la entrada del directorio,b
su contenido ya ha sido procesado. Por-prune
lo tanto, es ineficaz con-depth
efecto.-delete
implica-depth
para que pueda eliminar primero los archivos y luego el directorio vacío.-delete
se niega a eliminar directorios no vacíos. Supongo que sería posible agregar una opción para forzar la-delete
eliminación de directorios no vacíos y / o para evitar-delete
que 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
b
y procesa cada archivo solo para-not
rechazarlos. Esto puede ser un problema de rendimiento si el directoriob
es enorme.-path
funciona de manera diferente-name
.-name
solo coincide con el nombre (del archivo o directorio) mientras-path
coincide con la ruta completa. Por ejemplo, observar el camino/home/lesmana/foo/bar
.-name -bar
coincidirá porque el nombre esbar
.-path "*/foo*"
coincidirá porque la cadena/foo
está en la ruta.-path
tiene algunas complejidades que debes entender antes de usarlo. Lea la página de manual defind
para 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 comienceb
independientemente 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
a
yb
como marcadores de posición y los nombres reales son más comoallosaurus
ybrachiosaurus
. Si lo colocabrachiosaurus
en 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 -path
fue justo la cosa! Gracias por una generosa explicación!-not -path
funciona mientras-prune
que no es útil. ¿Por qué puede-not -path
coexistir con-depth
?Solo use en
rm
lugar de-delete
:fuente
rm
funciona ydelete
no funciona?rm
no tiene ese problema. Pero, independientemente, la elaboración sería algo bueno.-delete
implica-depth
, que obviamente no puede funcionar-prune
.-path
funciona, pero no dejafind
de 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