Jak w systemie Linux mogę znaleźć wszystkie pliki zawierające ciąg i je usunąć?

17

Chcę usunąć wszystkie pliki zawierające ciąg foo. Jak mogę to zrobić za pomocą bash w systemie Linux?

Kitsos
źródło
ten ciąg to nazwa pliku?
rɑːdʒɑ
3
Wyjaśnij: czy chcesz usunąć pliki, których nazwa zawiera foo(np. myfoo.jpg), Czy pliki zawierające sekwencję bajtów foo(które mogą obejmować pliki binarne, które akurat zawierają sekwencję bajtów)?
hammar

Odpowiedzi:

33

Oto bezpieczny sposób:

grep -lrIZ foo . | xargs -0 rm -f --
  • -l drukuje nazwy plików pasujących do wzorca wyszukiwania.
  • -rwykonuje rekurencyjne wyszukiwanie wzorca foow podanym katalogu .. Jeśli to nie zadziała, spróbuj -R.
  • -I(kapitał i) powoduje pomijanie plików binarnych, takich jak pliki PDF.
  • -Z zapewnia, że ​​nazwy plików są zerowane (tj. nul-), tak aby nazwa zawierająca białe znaki nie była interpretowana w niewłaściwy sposób (tzn. jako wiele nazw zamiast jednej).
  • xargs -0podaje nazwy plików od grepdo rm -f, oddzielając słowa przez zero (nul) bajtów (pamiętaj -Zopcję od grep).
  • --jest często zapominany, ale bardzo ważne jest zaznaczenie końca opcji i umożliwienie usunięcia plików, których nazwy zaczynają się -.

Jeśli chcesz zobaczyć, które pliki mają zostać usunięte, po prostu usuń | xargs -0 rm -f --część i pozostaw Zopcję grep.

Inny użytkownik zasugerował coś takiego, czego nie należy uruchamiać, ponieważ jest to niebezpieczne:

files=`grep foo * | cut -d: -f1`
rm -f $files         # unsafe, do not run it!

Jeśli mam pliki ImportantStuff, których nie chcę usuwać i które obsolete ImportantStuffzawierają foo, tracę ImportantStuff(i nie obsolete ImportantStuff !) Po uruchomieniu tego polecenia, ponieważ $filesrozpada się na spacje podczas interpretacji. W ten sposób umieszczanie listy nazw plików w zmiennej powłoki skalarnej jest niebezpieczne.

Lekensteyn
źródło
17
$ find -type f -exec grep -q "foo" {} \; -exec echo rm -- {} \;

Rekurencyjnie wyszukuje pliki zawierające foo . Drugi -execjest uruchamiany tylko wtedy, gdy pierwszy execzakończy się pomyślnie, tzn. Jeśli greppasuje. Dryrun i usuń, echojeśli wyjście wydaje się prawidłowe.

Lub alternatywnie

$ find -type f -exec grep -q "foo" {} \; -print

i

$ find -type f -exec grep -q "foo" {} \; -delete

jak sugeruje Lekensteyn.

Adrian Frühwirth
źródło
4
... które można skrócić do: find -type f -exec grep -q 'foo' {} \; -delete(cytaty {}są zbędne, findmożna także usuwać pliki). Uwaga: grepakceptuje wyrażenie regularne. Jeśli chcesz wyszukać foo.bar, albo uniknij tego, albo przekaż -Fopcję traktowania wzorca jako dosłownego.
Lekensteyn,
jakiś powód do korzystania, -exec echo rm "{}" \;a nie -delete?
vartec
1
@vartec Nie, skorzystałbym -delete. Łatwiej jest zademonstrować z drugim -execi rozbrzmiewającym echem.
Adrian Frühwirth
1
Łatwiej jest pisać -print(lub -lsdla większej szczegółowości) niż -exec echo rm "{}" \'. Nie potrzeba zewnętrznych narzędzi.
Lekensteyn,
1
jeśli używasz rm {}, użyj rm - {}, aby żadne znaki specjalne w samej nazwie pliku nie były interpolowane. Na przykład dotknij „-rf /” w dowolnym katalogu, w którym masz uprawnienia do zapisu ...
atk
1

Zrobiłbym to, co mówi Adrian,

Ale dodam granice słów wokół foo, aby przypadkowo nie usunąć plików zawierających „jedzenie” (chyba że usuwa wszystko, co zawiera jedzenie).

 $ find -type f -exec grep -q "\<foo\>" {} \; -delete

acutally, przekierowałem dane wyjściowe przed usunięciem, aby móc przejrzeć przed usunięciem:

 $ find -type f -exec grep -q "\<foo\>" > /tmp/list_of_files_to_delete
Petter H.
źródło
Jak tylko będziesz mógł dodawać komentarze, powinieneś zamieścić takie rzeczy jako komentarze.
FSMaxB 21.04.13
tak, najpierw próbowałem, ale potem zdałem sobie sprawę, że nie mogę jeszcze dodawać komentarzy.
Petter H