Jak usunąć katalogi na podstawie danych wyjściowych `find`?


148

Wydaję następujące polecenie, aby znaleźć katalogi .svn:

find . -name ".svn"

To daje mi następujące wyniki:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

Jak mogę przetworzyć wszystkie te wiersze rm -fr, aby usunąć katalogi i ich zawartość?


3
GNU find ma -deleteopcję.
Marco

5
Lub możesz dodać -exec rm -r "{}" \;na końcu znaleziska - zachowaj ostrożność podczas używania rm -r! :)
Drav Sloan,

10
@Marco Opcja usuwania nie działa na katalogach.
Arnaud

@SuperChafouin Działa doskonale tutaj w plikach i katalogach. Chodzi o to, że usuwa tylko katalogi emtpy, a gdy określisz -name ".svn", pasuje tylko do .svnsamego katalogu, a nie do plików znajdujących się w .svnkatalogu.
Marco

1
@SuperChafouin, ale nie będzie działać dla ścieżek ze spacjami w nich (stąd używanie -execcudzysłowu "{}").
Drav Sloan,

Odpowiedzi:


194

Znajdź może wykonywać argumenty z -execopcją dla każdego znalezionego dopasowania. Jest to zalecany mechanizm, ponieważ można poprawnie obsługiwać ścieżki ze spacjami / znakami nowej linii i innymi znakami. Będziesz musiał usunąć zawartość katalogu, zanim będziesz mógł usunąć sam katalog, więc użyj -rtego rmpolecenia, aby to osiągnąć.

Na przykład możesz wydać:

find . -name ".svn" -exec rm -r "{}" \;

Możesz także powiedzieć find, aby po prostu znalazł katalogi o nazwie .svn, dodając znacznik -type d:

find . -name ".svn" -type d -exec rm -r "{}" \;

Ostrzeżenie Używaj rm -rostrożnie, ponieważ usuwa folder i całą jego zawartość.

Jeśli chcesz usunąć tylko puste katalogi, a także katalogi, które zawierają tylko puste katalogi, znaleźć można zrobić sobie z -deletei -empty:

find . -name ".svn" -type d -empty -delete

21
Widziałem rady zawsze uruchamiane -type po -name poleceń znalezienia, ponieważ wywołania stataby uzyskać typu są drogie. Właśnie wypróbowałem to na dość dużej grupie plików i wydaje się to prawdą: uruchomienie find . -name 'foo' -type dzajęło 19 sekund, podczas gdy find . -type d -name 'foo'zajęło 32 sekundy. Więc o 50% dłuższy czas na uruchomienie -type.
spinup

6
Korzystam z tego polecenia od lat, ale teraz na Macu pojawiają się błędy informujące, że te katalogi nie istnieją. Mimo że je usuwa. Nigdy wcześniej nie widziałem wiadomości.
chovy

1
Taki sam jak @chovy. Czy istnieje sposób na pozbycie się tych wiadomości?
Clément

2
@chovy @ clément To dlatego, że findchce zobaczyć w tym folderze inne dopasowania, jednocześnie usuwając folder w tym samym czasie. ~ Nie wiem jeszcze, jak to naprawić. ~ Brudna poprawka:find . -name "folder-to-delete" -print0 | xargs -r0 -- rm -r
Charlie,

5
@chovy @ Clément Myślę, że ten -depthargument to naprawia:find . -depth -name ".svn" -type d -exec rm -r "{}" \;
gimboland

67

Oto przenośny wciąż szybszy niż akceptowany sposób odpowiedzi.

Użycie +zamiast średnika jako findterminatora poleceń optymalizuje użycie procesora. Może to być znaczące, jeśli masz wiele .svnpodkatalogów:

find . -name .svn -type d -exec rm -rf {} +

Należy również zauważyć, że nigdy 1 trzeba zacytować nawiasów klamrowych tutaj.

1 Chyba że użyjesz fishmuszli.


5
Jaka jest różnica między znakiem + i średnikiem? Dlaczego nie używamy nawiasów klamrowych?
Shicheng Guo

1
@ShichengGuo Z średnikiem będzie jedno polecenie rm na katalog, a + jedno polecenie rm przetworzy wszystkie znalezione katalogi (lub przynajmniej bardzo dużą ich liczbę). Nie dostaję drugiego pytania, kędzierzawy stosowane są tutaj szelki.
jlliagre

Myślę, że @ShichengGuo oznacza, dlaczego nie musimy cytować tutaj nawiasów klamrowych (@jlliagre napisał, że nigdy nie musimy ich cytować). Nie mogę teraz znaleźć odniesienia, ale rozumiem, że ponieważ find automatycznie ucieknie od ścieżek zastąpionych przez {}.
Quinn Comendant

Odpowiedź i pytanie nie są do końca zgodne z tym, co robi +. Jeśli znaleziono wiele plików, to „;” dawałby błąd „zbyt długa linia poleceń”. + dzieli pliki znalezione w partiach, które są mniejsze niż maksymalna dozwolona długość wiersza poleceń i uruchamia polecenie dla każdej partii.
gaoithe

1
@ gaoithe Zrobiłem wycofywanie edytowałeś, który zastąpił prawidłowe oświadczenie niewłaściwym. Używanie + ma zmniejszyć zużycie procesora, używając ; nie doprowadzić do polecenia zbyt długo błędu.
jlliagre

27

Załóżmy, że używasz GNU Find , możesz użyć -deleteopcji:

find . -name test -delete

co jest łatwiejsze do zapamiętania.


Rozważ rozwinięcie swojego posta z objaśnieniem polecenia (lub dokumentacją do wykonania kopii zapasowej rozwiązania). Często jedna (lub dwie) odpowiedzi liniowe nie są najlepiej oświetlające.
HalosGhost,

93
To nie działa na niepustych katalogach.
belacqua

2
działa również w systemie Mac OS X
losowanie

To nie działa w przypadku niepustych folderów, ale jest to łatwiejsze i bezpieczniejsze rozwiązanie
RousseauAlexandre

Kolejność opcji jest bardzo ważna, find wykona je w kolejności, więc -delete musi być ostatni
Jose Ignacio Centeno

13

Gdy korzystam z komputera:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'

Katalogi zostały usunięte, ale pojawia się błąd:

find: ‘./dirname’: No such file or directory

dla każdego katalogu.

Moje katalogi nie są puste, więc opcja -delete nie będzie dla mnie działać. Znalazłem przyczynę tego zachowania tutaj :

  1. find bierze (niekoniecznie) pierwszy wpis w katalogu ./. byłoby to np. reż. 1 /
  2. porównuje to do wzoru „reż.?”. czy to pasuje? tak.
  3. find wykonuje „rm -r reż.1”.
  4. find próbuje wpisać katalog 1 /, aby znaleźć wzorzec w katalogu. nic nie wie o komendzie exec.
  5. nie znajduje już reż. 1 /. zwraca ENOENT (spójrz na dane wyjściowe strace)

Użyłem tego zamiast tego do obejścia:

rm -r `find . -name dirname -type d`

Pamiętaj, że find nadal będzie próbował przekierować do katalogów o nazwie dirname, co nie jest tak naprawdę konieczne i zajmie trochę więcej czasu. W zależności od struktury katalogów możesz obejść ten problem za pomocą --depthopcji find. Ponadto, jeśli masz strukturę katalogów, taką jak dirname / foo / dirname, otrzymasz od rm błędy „Brak takiego pliku lub katalogu”. Aby stłumić błędy, możesz przekierować stderr na / dev / null lub użyć -fflagi (force) za pomocą rm.


2
Zły pomysł: nazwa pliku ze spacjami spowoduje różnego rodzaju okropne problemy
Clément

2
Dla przyszłych czytelników: find . -name "to-delete" -print0 | xargs -r0 -- rm -rjest odporną na awarie wersją, która nie ulega awarii na przestrzeniach
Charlie,

3
Zobacz unix.stackexchange.com/a/115869/8257, który musisz dodać -prune.
Mapio

1
Dodaj, -pruneaby uniknąć błędu „Brak takiego pliku lub katalogu”.
Julien Carsique

12

Szybszym sposobem na to jest:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

Jeśli masz „.svn” w innym „.svn”.


Nie jest to bardzo przydatne, jeśli chcesz znaleźć katalogi do usunięcia z podkatalogami.
Alexis Wilke,

5

Rozwiązanie specyficzne dla Bash:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion

3
Uwaga: w przypadku rozszerzania globów wiersza poleceń pasujących do wielu plików istnieje ograniczenie liczby plików, które można dopasować za pomocą tego mechanizmu. bash: /bin/rm: Argument list too long
Przekroczenie

1
@DravSloan jest poprawny, ale ten limit jest w setkach tysięcy plików. Należy o tym pamiętać, ale prawdopodobnie nie będzie to problemem dla większości ludzi.
evilsoup

4

Przekonałem się, że -deleteakcja działa dobrze z -pathtestem. Na przykład następujące problemy powinny rozwiązać problem z oryginalnymi plakatami:

find . -path '*/.svn*' -delete

Jesteś pewny? -deleteoznacza -depth, i z pewnością usuwa niepuste katalogi w moim systemie.
Magnus,

Ponownie przetestowane i działa. Może to tylko literówka, którą poprawiłem.
kenorb

Próbowałem również tego podejścia i zadziałało - katalogi zostały usunięte.
Allan
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.