¿Por qué find con -delete borró los archivos en mi directorio / save / cuando find sin eliminar no pudo localizarlos?

20

Quiero eliminar todos los archivos en el árbol de directorios actual, excepto aquellos en save. Ejecuté este comando:

 find . \( -name save -prune \) -o -type f -ls | grep /save/

y no encontró ninguno. Pero cuando ejecuté este comando:

 find . \( -name save -prune \) -o -type f -delete

Todos esos archivos en / save / desaparecieron. ¿Qué me estoy perdiendo?

Oteo
fuente
44
Ay ... aprendí algo hoy (gracias a ti). Y recomiendo un simple mv save/ ../some/safer/locationantes de un comando de eliminación "genérico" (... pero, por supuesto, antes de su publicación, habría hecho la misma verificación y me encontré con el mismo problema). Ahora ve a buscar un buen "recuperar" para el sistema de archivos donde estaban los archivos ^^
Olivier Dulac
3
Mi dolor es tu prevención.
Oteo
1
1000 gracias a ti. Code (¿a menudo?) Funciona de manera misteriosa ...
Olivier Dulac
@lesmana Voté tu respuesta allí. tristemente, mi versión de find no me da una advertencia tan agradable :(
Otheus

Respuestas:

26

-deleteimplica -depthque no funciona con -prune( -depthcomienza con las hojas). Hay una advertencia al respecto en el manual de la versión de GNU ( -deletees una extensión de FreeBSD que ahora también es compatible con GNU findy algunas otras implementaciones).

info find --index-search=-delete

El uso de la acción '-delete' en la línea de comando activa automáticamente la opción '-depth' (* note find Expressions: :). Esto puede ser sorprendente si anteriormente solo estaba probando con '-print', por lo que generalmente es mejor recordar usar '-depth' explícitamente.

info find --index-search=-prune

Debido a que '-delete' implica '-depth', usar '-prune' en combinación con '-delete' puede resultar en la eliminación de más archivos de los que pretendía.

Aquí, tienes la opción de usar en su rmlugar:

find . -name save -prune -o -type f -exec rm -f {} +

(potencialmente inseguro si hay un directorio que otros puedan escribir allí, ya que uno podría hacer que elimine archivos fuera del árbol de directorios actual al reemplazar los directorios con enlaces simbólicos mientras ejecuta ese comando).

Una alternativa más segura:

find . -name save -prune -o -type f -execdir rm -f -- {} \;

Eso no tiene el problema mencionado anteriormente, pero significa ejecutar uno rmpor archivo. El --es necesario para la implementación de FreeBSD, no el GNU que prefija los nombres de archivo ./.

Alternativamente, como lo sugiere Costas:

LC_ALL=C find . ! -name save ! -path '*/save/*' -type f -delete

(pero eso aún desciende innecesariamente en savedirectorios)

El LC_ALL=Cestá allí, por lo que *coincide con cualquier secuencia de bytes (incluso aquellos que no forman caracteres válidos en la configuración regional actual). Tenga en cuenta que afectará el idioma de los mensajes de error (inglés en lugar del idioma del usuario).

Stéphane Chazelas
fuente
¿Cuál es el problema de seguridad aquí rm?
jrw32982 es compatible con Monica el
@ jrw32982, ver edición con enlace al manual de búsqueda de GNU
Stéphane Chazelas