Quiero eliminar recursivamente todos los archivos a los que no se accedió en 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 activa automáticamente - depth, pero -prune no
hace nada cuando - depth está en efecto. Si desea continuar de todos modos,
simplemente use explícitamente la opción -profundidad.
Agregando -depth hace que todos los archivos en b a incluir, que no suceder.
¿Alguien conoce una forma segura de hacer que esto funcione?
Respuesta aceptada:
una forma es usar -exec rm en lugar de -delete .
find a ( -name b -prune ) -o -type f -exec rm {} +
alternativamente use -not -path en lugar de -prune :
find a -not -path "*/b*" -type f -delete
Explicación por qué -prune colisiona con -delete :
encuentra quejas cuando intentas usar -delete con -prune porque -delete implica -depth y -depth hace -prune ineficaz.
observe el comportamiento de find 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 orden en un solo directorio. Pero hay una garantía de que un directorio se procesa antes que su contenido. Nota foo/ antes de cualquier foo/* y foo/bar antes de cualquier 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 los foo/* aparecer antes de foo/ . Lo mismo con foo/bar .
más explicación:
-pruneevita que find descienda a un directorio. En otras palabras-prunesalta el contenido del directorio. En tu caso-name b -prunesignifica que cuando find llega a un directorio con el nombrebomitirá el directorio, incluidos todos los subdirectorios.-depthhace que find procese el contenido de un directorio antes que el propio directorio. Eso significa que para cuando find llegue a procesar la entrada del directoriobsu contenido ya ha sido procesado. Así-prunees ineficaz con-depthen vigor.-deleteimplica-depthpara que pueda eliminar primero el contenido y luego el directorio vacío.-deletese niega a eliminar directorios que no estén vacíos.
Explicación del método alternativo:
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 en él solo para -not para rechazarlos. Esto puede ser un problema de rendimiento si el directorio b es enorme.
-path funciona de manera diferente a -name . -name solo coincide con el nombre (del archivo o directorio) mientras que -path coincide con la ruta completa. Por ejemplo observe la ruta /home/lesmana/foo/bar . -name bar coincidirá porque el nombre es bar . -path "*/foo*" coincidirá porque la cadena /foo está en el camino. -path tiene algunas complejidades que debe comprender antes de usarlo. Lea la página man 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 está escrito arriba omitirá cualquier archivo que tenga un directorio principal cuyo nombre comience con b (positivo). Pero también omitirá cualquier archivo cuyo nombre comience con 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 se parecen más a allosaurus y brachiosaurus . Si pones brachiosaurus en lugar de b entonces la cantidad de falsos positivos se reducirá drásticamente.
Al menos los falsos positivos serán no eliminado, por lo que no será tan trágico. Además, puede verificar si hay falsos positivos ejecutando primero el comando sin -delete (pero recuerda colocar la -depth implícita ) y examine la salida.
find a -not -path "*/b*" -type f -depth