TL; DR: la mejor manera es usar en -exec rm
lugar de -delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
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
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
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/
antes foo/*
y foo/bar
antes de cualquiera foo/bar/*
.
Esto se puede revertir con -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Tenga en cuenta que ahora todos foo/*
aparecen antes foo/
. Lo mismo con foo/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 nombre b
.
-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:
find a -not -path "*/b*" -type f -delete
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 directorio b
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 es bar
. -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 de find
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 comience b
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
y b
como marcadores de posición y los nombres reales son más como allosaurus
y brachiosaurus
. Si lo coloca brachiosaurus
en su lugar b
, 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.
find a -not -path "*/b*" -type f -depth
a
exceptoa/b
?