¿Por qué 'find -delete' elimina todos los archivos de un directorio de forma recursiva?

15

Entonces, el siguiente comportamiento de unix find me costó caro:

> touch foo
> touch bar
> ls  
bar  foo
> find . -name '*oo' -delete
> ls
bar
> touch baz
> ls
bar  baz
> find . -delete -name '*ar'
> ls
> #WHAAAT?

¿Cómo esto tiene sentido?

mszep
fuente
2
Esta pregunta está relacionada, podría ser interesante para futuros lectores. unix.stackexchange.com/questions/101282/…
Bernhard

Respuestas:

14

La línea de comando de find está hecha de diferentes tipos de opciones, que se combinan para formar expresiones.

La findopción -deletees una acción.
Eso significa que se ejecuta para cada archivo que coincida hasta ahora.
Como primera opción después de las rutas, todos los archivos coinciden ... ¡Uy!

Es peligroso, pero la página de manual al menos tiene una gran advertencia :

De man find:

ACTIONS
    -delete
           Delete  files; true if removal succeeded.  If the removal failed, an
           error message is issued.  If -delete fails, find's exit status  will
           be nonzero (when it eventually exits).  Use of -delete automatically
           turns on the -depth option.

           Warnings: Don't forget that the find command line is evaluated as an
           expression,  so  putting  -delete first will make find try to delete
           everything below the starting points you specified.  When testing  a
           find  command  line  that  you later intend to use with -delete, you
           should explicitly specify -depth in order to avoid later  surprises.
           Because  -delete  implies -depth, you cannot usefully use -prune and
           -delete together.


De más arriba en man find:

EXPRESSIONS
    The expression is made up of options (which affect overall operation rather
    than  the  processing  of  a  specific file, and always return true), tests
    (which return a true or false value), and actions (which have side  effects
    and  return  a  true  or false value), all separated by operators.  -and is
    assumed where the operator is omitted.

    If the expression contains no actions other than  -prune,  -print  is  per‐
    formed on all files for which the expression is true.


Al probar lo que findhará un comando:

Para ver cómo es un comando

find . -name '*ar' -delete

eliminará, primero puede reemplazar la acción -deletepor una acción más inofensiva, como -flso -print:

find . -name '*ar' -print

Esto imprimirá qué archivos se ven afectados por la acción.
En este ejemplo, la impresión se puede omitir. En este caso, no es acción en absoluto, por lo que la más obvia se añade de forma implícita: -print. (Ver el segundo párrafo de la sección "EXPRESIONES" citado anteriormente)

Volker Siegel
fuente
Supongo que era un idiota por no haber leído el manual primero ... Pero parecía tan sencillo agregar la -deletebandera :-) Pero, ¿hay alguna razón por la que alguien pueda hacerlo en find . -deletelugar de hacerlo rm -rf .? ¿O es que esa es la forma en que findanaliza y procesa sus argumentos?
mszep
1
Oh, estoy totalmente de acuerdo en que la sintaxis es muy peligrosa , pero eso es difícil de evitar, ya que es solo un caso especial de la sintaxis de expresión de línea de comando de find, que es extremadamente poderosa. Potente como en " Una poderosa motosierra ".
Volker Siegel
¿No dice la página del manual citada warning: use -depth when testing stuff you later want to -deletelo que no hizo en su ejemplo práctico?
pqnet
Ah, claro, el problema es el encabezado. Quería ilustrar el uso de la impresión en lugar de -delete como una -nopción; El primer comando no debería tener ningún uso práctico, por supuesto; Iré a cambiarlo.
Volker Siegel
9

En el findorden el argumento importa, mucho.

Los argumentos pueden ser opciones, pruebas y acciones. Por lo general, debe usar primero las opciones, luego las pruebas y luego las acciones.

A veces, findincluso le advierte sobre un posible mal orden (por ejemplo, cuando lo usa -maxdepthdespués de otros argumentos), pero otros parece que no.

Lo que find . -delete -name '*ar'hace es:

  1. Encuentra archivos y directorios en el directorio actual.
  2. ¡Los elimina TODOS a medida que se encuentran!
  3. Luego ve si se nombran como '* ar' (esta parte no tiene ningún efecto ahora).

Lo que probablemente quieras hacer es:

find -name '*ar' -delete

Esto, para cada archivo, verá si coincide '*ar', y solo si cumple con la condición eliminará el archivo.

Lo siento si te enteraste demasiado tarde.

LatinSuD
fuente