Як в Linux можна знайти всі файли, що містять рядок, і видалити їх?


17

Я хочу видалити всі файли, що містять рядок foo. Як я можу це зробити за допомогою bash в Linux?


що рядок - це ім'я файлу?
rɑːdʒɑ

3
Поясніть, будь ласка, ви хочете видалити файли, чиє ім'я містить foo(наприклад myfoo.jpg), або файли, що містять послідовність байтів foo(які можуть включати бінарні файли, які так часто містять цю послідовність байтів)?
hammar

Відповіді:


33

Ось безпечний спосіб:

grep -lrIZ foo . | xargs -0 rm -f --
  • -l друкує назви файлів, що відповідають шаблону пошуку.
  • -rздійснює рекурсивний пошук шаблону fooв заданому каталозі .. Якщо це не працює, спробуйте -R.
  • -I(велика літера i) призводить до пропускання двійкових файлів, таких як PDF.
  • -Z гарантує, що імена файлів закінчуються нулем (тобто нульовим), так що ім'я, що містить пробіл, не трактується неправильно (тобто, як кілька імен замість одного).
  • xargs -0подає імена файлів від grepдо rm -f, розділяючи слова на нуль (нуль) байтів (запам'ятайте -Zваріант від grep).
  • --часто забувається, але дуже важливо позначити кінець параметрів і дозволити видалення файлів, імена яких починаються з -.

Якщо ви хочете побачити, які файли збираються видалити, просто видаліть | xargs -0 rm -f --частину і залиште Zопцію " grep.

Інший користувач запропонував щось подібне до цього, чого не слід запускати, оскільки це небезпечно:

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

Якщо у мене є файли, ImportantStuffякі я не хочу видаляти і obsolete ImportantStuffмістять foo, то я втрачаю ImportantStuffні obsolete ImportantStuff !), Коли виконую цю команду, тому що вона $filesрозбивається на пробіли, коли вона інтерпретується. Небезпечно таким чином ставити список імен файлів у скалярну змінну оболонки.


17
$ find -type f -exec grep -q "foo" {} \; -exec echo rm -- {} \;

Цей рекурсивно шукає файли, що містять foo. Другий -execзапускається лише в тому випадку, якщо перший execзакінчується успішно, тобто якщо grepвідповідає. Dryrun і видаліть, echoякщо вихід здається правильним.

Або в якості альтернативи

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

і

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

як запропонував Лекенштейн.


4
... яку можна скоротити до: find -type f -exec grep -q 'foo' {} \; -delete(цитати навколо {}є зайвими, findтакож може видаляти файли.). Зауважте, що grepприймає регулярний вираз. Якщо ви хочете шукати foo.bar, уникайте цього або перейдіть до -Fпараметра, щоб трактувати шаблон як буквальний.
Лекенштейн

будь-яка причина використовувати -exec echo rm "{}" \;і ні -delete?
vartec

1
@vartec Ні, я б використовував -delete. Просто простіше продемонструвати друге -execі відлуння на місці.
Адріан Фрюхвірт

1
Це простіше набрати -print(або -lsдля більш багатослівного), ніж -exec echo rm "{}" \'. Немає потреби у зовнішніх утилітах.
Лекенштейн

1
якщо ви використовуєте rm {}, використовуйте rm - {}, щоб будь-які спеціальні символи у самій назві файлу не були інтерпольовані. Наприклад, торкніться "-rf /" у будь-якому каталозі, де у вас є дозволи на запис ...
atk

1

Я зробив би те, що каже Адріан,

Але я б додав межі слів навколо foo, щоб не випадково видалити файли, що містять "їжу" (якщо тільки ви не видаляєте все, що містить їжу, те, що ви хочете.)

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

акутно, я переспрямував би результат перед видаленням, щоб я міг переглянути перед видаленням:

 $ find -type f -exec grep -q "\<foo\>" > /tmp/list_of_files_to_delete

Як тільки ви зможете публікувати коментарі, ви повинні публікувати такі речі як коментарі.
FSMaxB

так, я спробував спочатку, але потім зрозумів, що мені поки що не дозволяють публікувати коментарі.
Петтер Н
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.