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:
-prune
evita que find descienda a un directorio. En otras palabras-prune
salta el contenido del directorio. En tu caso-name b -prune
significa que cuando find llega a un directorio con el nombreb
omitirá el directorio, incluidos todos los subdirectorios.-depth
hace 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 directoriob
su contenido ya ha sido procesado. Así-prune
es ineficaz con-depth
en vigor.-delete
implica-depth
para que pueda eliminar primero el contenido y luego el directorio vacío.-delete
se 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