Dlaczego polecenie „znajdź -delete” usuwa rekursywnie wszystkie pliki w katalogu

15

Więc następujące zachowanie unixa kosztuje mnie bardzo drogo:

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

Jak to ma sens?

mszep
źródło
2
To pytanie jest powiązane, może być interesujące dla przyszłych czytelników. unix.stackexchange.com/questions/101282/…
Bernhard

Odpowiedzi:

14

Wiersz polecenia find zawiera różne opcje, które są łączone w wyrażenia.

findOpcja -deletejest działaniem.
Oznacza to, że jest wykonywany dla każdego pasującego do tej pory pliku.
Jako pierwsza opcja po ścieżkach wszystkie pliki są dopasowane ... Ups!

Jest to niebezpieczne - ale strona podręcznika ma przynajmniej duże ostrzeżenie :

Od 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.


Z dalszej części 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.


Po wypróbowaniu, co findzrobi polecenie:

Aby zobaczyć, jak lubi polecenie

find . -name '*ar' -delete

usunie, możesz najpierw zastąpić akcję -deletebardziej nieszkodliwym działaniem - takim jak -flslub -print:

find . -name '*ar' -print

Spowoduje to wydrukowanie plików, na które akcja ma wpływ.
W tym przykładzie -print można pominąć. W tym przypadku, nie ma działania w ogóle, więc najbardziej oczywistym jest dodawane domyślnie: -print. (Zobacz akapit drugi w sekcji „WYRAŻENIA” cytowanej powyżej)

Volker Siegel
źródło
Chyba po prostu idiotą, że nie czyta instrukcji pierwszy .. Ale to wydawało się tak proste do wystarczy dodać -deleteflagę :-) Ale czy istnieje jakiś powód, by ktoś kiedykolwiek zrobić find . -deletezamiast rm -rf .? A może tak właśnie się dzieje, gdy findanalizuje i przetwarza swoje argumenty?
mszep
1
Och, w pełni się zgadzam, że składnia jest bardzo niebezpieczna - ale tego trudno uniknąć, ponieważ jest to tylko szczególny przypadek składni wyrażenia linii komendowej find, która jest niezwykle potężna. Mocny jak w „Potężnej pilarce łańcuchowej ”.
Volker Siegel,
czy cytowana strona podręcznika nie wskazuje warning: use -depth when testing stuff you later want to -deletetego, czego nie zrobiłeś na praktycznym przykładzie?
pqnet,
Och, racja - problemem jest nagłówek - chciałem zilustrować użycie nadruku zamiast -nopcji -delete ; Oczywiście pierwsze polecenie nie powinno mieć żadnego praktycznego zastosowania; Pójdę to zmienić.
Volker Siegel,
9

Bardzo findważna jest kolejność argumentów.

Argumentami mogą być opcje, testy i akcje. Zazwyczaj powinieneś najpierw użyć opcji, potem testów, a następnie akcji.

Czasami findnawet ostrzega cię przed możliwym złym uporządkowaniem (na przykład, gdy używasz -maxdepthinnych argumentów), ale innym wydaje się, że tak nie jest.

Co find . -delete -name '*ar'to jest:

  1. Znajduje pliki i katalogi w bieżącym katalogu.
  2. Usuwa je WSZYSTKO, gdy zostaną znalezione!
  3. Następnie sprawdza, czy są nazwane jak „* ar” (ta część nie ma teraz efektu).

Prawdopodobnie chcesz to zrobić:

find -name '*ar' -delete

Spowoduje to, dla każdego pliku, czy pasuje '*ar', i tylko jeśli spełni warunek, usunie plik.

Przepraszam, jeśli dowiedziałeś się za późno.

LatinSuD
źródło