Dlaczego funkcja find -delete usunęła pliki w moim katalogu / save /, gdy funkcja find bez usuwania nie mogła ich zlokalizować?

20

Chcę usunąć wszystkie pliki z bieżącego drzewa katalogów, z wyjątkiem tych z save. Uruchomiłem to polecenie:

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

i nie znalazł żadnego. Ale kiedy uruchomiłem to polecenie:

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

Wszystkie te pliki w / save / zniknęły. czego mi brakuje?

Otheus
źródło
4
Ojej… Nauczyłem się dziś czegoś (dzięki tobie). I polecam proste mv save/ ../some/safer/locationprzed takim „ogólnym” poleceniem usuwania (... ale oczywiście przed twoim postem zrobiłbym to samo sprawdzenie i napotkałem ten sam problem!). Teraz znajdź dobre „cofnięcie usunięcia” dla systemu plików, w którym pliki były na ^^
Olivier Dulac
3
Mój ból jest twoją prewencją.
Otheus
1
1000 dzięki tobie. Kod (często?) Działa w tajemniczy sposób ...
Olivier Dulac
@lesmana Poparłem tam twoją odpowiedź. niestety moja wersja znalezienia nie daje mi tak miłego ostrzeżenia :(
Otheus

Odpowiedzi:

26

-deleteoznacza, -depthże nie działa -prune( -depthzaczyna się od liści). Jest o tym ostrzeżenie w podręczniku wersji GNU ( -deletejest to rozszerzenie FreeBSD obsługiwane teraz także przez GNU findi kilka innych implementacji).

info find --index-search=-delete

Użycie akcji „-delete” w wierszu poleceń automatycznie włącza opcję „-depth” (* notatka znajdź Wyrażenia: :). Może to być zaskakujące, jeśli wcześniej testowałeś tylko z „-print”, więc zazwyczaj najlepiej jest pamiętać, aby używać „-depth” wyraźnie.

info find --index-search=-prune

Ponieważ „-delete” oznacza „-depth”, użycie „-prune” w połączeniu z „-delete” może skutkować usunięciem większej liczby plików niż zamierzałeś.

Tutaj masz opcję użycia rmzamiast tego:

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

(potencjalnie niebezpieczne, jeśli istnieją katalogi do zapisu przez innych, ponieważ można spowodować usunięcie plików poza bieżącym drzewem katalogów poprzez zastąpienie katalogów dowiązaniami symbolicznymi podczas uruchamiania tej komendy).

Bezpieczniejsza alternatywa:

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

To nie ma wyżej wspomnianego problemu, ale oznacza uruchomienie jednego rmna plik. Jest --to konieczne do implementacji FreeBSD, a nie GNU, który poprzedza nazwy plików ./.

Alternatywnie, jak sugeruje Costas:

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

(ale to wciąż niepotrzebnie schodzi do savekatalogów)

LC_ALL=CJest tak *dopasowuje dowolną sekwencję bajtów (nawet tych, które nie tworzą poprawnych znaków w bieżącej lokalizacji). Pamiętaj, że wpłynie to na język komunikatów o błędach (angielski zamiast języka użytkownika).

Stéphane Chazelas
źródło
Z czym jest tutaj problem bezpieczeństwa rm?
jrw32982 obsługuje Monikę
@ jrw32982, patrz edycja z linkiem do instrukcji GNU find
Stéphane Chazelas