Як в 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.