TL; DR: la mejor manera es usar en -exec rmlugar de -delete.
find a \( -name b -prune \) -o -type f -exec rm {} +
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:
$ 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/barantes 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:
-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 nombre b.
-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:
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 by procesa cada archivo solo para -notrechazarlos. Esto puede ser un problema de rendimiento si el directorio bes 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 es bar. -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 de findpara 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 bindependientemente 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 ay bcomo marcadores de posición y los nombres reales son más como allosaurusy brachiosaurus. Si lo coloca brachiosaurusen 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
aexceptoa/b?