Por que 'find -delete' exclui todos os arquivos em um diretório recursivamente

15

Portanto, o seguinte comportamento do unix find me custou muito:

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

Como isso faz sentido?

mszep
fonte
2
Esta questão está relacionada, pode ser interessante para futuros leitores. unix.stackexchange.com/questions/101282/…
Bernhard

Respostas:

14

A linha de comando de localização é feita a partir de diferentes tipos de opções, combinadas para formar expressões.

A findopção -deleteé uma ação.
Isso significa que é executado para cada arquivo correspondido até o momento.
Como primeira opção após os caminhos, todos os arquivos são correspondidos ... oops!

É perigoso - mas a página de manual tem pelo menos um grande aviso :

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.


Mais adiante em 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.


Ao experimentar o que um findcomando fará:

Para ver como é um comando

find . -name '*ar' -delete

excluir, você pode substituir a ação -deletepor uma ação mais inofensiva - como -flsou -print:

find . -name '*ar' -print

Isso imprimirá quais arquivos são afetados pela ação.
Neste exemplo, a -print pode ser deixada de fora. Neste caso, não há ação em tudo, então o mais óbvio é adicionado implicitamente: -print. (Veja o segundo parágrafo da seção "EXPRESSÕES" citadas acima)

Volker Siegel
fonte
Eu acho que eu era apenas um idiota por não ler o manual primeiro .. Mas parecia tão simples de apenas adicionar o -deleteflag :-) Mas há alguma razão que ninguém jamais iria fazer find . -delete, em vez de rm -rf .? Ou será que é assim que findanalisa e processa seus argumentos?
mszep
1
Ah, concordo plenamente que a sintaxe é muito perigosa - mas isso é difícil de evitar, pois é apenas um caso especial da sintaxe da expressão de linha de comman de find, que é extremamente poderosa. Poderoso como em " Uma poderosa motosserra ".
Volker Siegel
a página do manual citado não diz o warning: use -depth when testing stuff you later want to -deleteque você não fez no seu exemplo prático?
Pqnet 17/08/2014
Ah, certo - o problema é o cabeçalho - pretendia ilustrar o uso da impressão no lugar de -delete como uma -nopção; O primeiro comando não deve ter nenhum uso prático, é claro; Eu vou mudar isso.
Volker Siegel
9

Na findordem dos argumentos importa muito.

Os argumentos podem ser opções, testes e ações. Você normalmente deve usar as opções primeiro, depois os testes e as ações.

Às vezes findaté avisa sobre uma possível má ordem (por exemplo, quando você usa -maxdepthdepois de outros argumentos), mas outras parece que não.

O que find . -delete -name '*ar'faz é:

  1. Localiza arquivos e diretórios no diretório atual.
  2. Exclui todos eles como são encontrados!
  3. Então, vê se eles são nomeados como '* ar' (esta parte não tem efeito agora).

O que você provavelmente quer fazer é:

find -name '*ar' -delete

Para cada arquivo, isso verificará se ele corresponde '*ar'e, somente se satisfizer a condição, o arquivo será excluído.

Desculpe se você descobriu tarde demais.

LatinSuD
fonte