В Linux, как я могу найти все файлы, содержащие строку, и удалить их?

17

Я хочу удалить все файлы, которые содержат строку foo. Как я могу сделать это, используя bash в Linux?

Kitsos
источник
эта строка является его именем файла?
rɑːdʒɑ
3
Пожалуйста, уточните: хотите ли вы удалить файлы, имя которых содержит foo(например, myfoo.jpg) или файлы, которые содержат последовательность байтов foo(которая может включать двоичные файлы, которые, как оказалось, содержат эту последовательность байтов)?
Хаммар

Ответы:

33

Вот безопасный способ:

grep -lrIZ foo . | xargs -0 rm -f --
  • -l печатает имена файлов, соответствующие шаблону поиска.
  • -rвыполняет рекурсивный поиск шаблона fooв заданном каталоге .. Если это не сработает, попробуйте -R.
  • -I(заглавная i) приводит к пропуску двоичных файлов, таких как PDF.
  • -Z гарантирует, что имена файлов заканчиваются на ноль (т. е. на ноль), чтобы имя, содержащее пробелы, не интерпретировалось неправильно (т. е. как несколько имен вместо одного).
  • xargs -0кормит имена файлов из grepto rm -f, разделяя слова на ноль (ноль) байтов (запомните -Zопцию from 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разбивается на пробелы, когда она интерпретируется. Таким образом, опасно помещать список имен файлов в скалярную переменную оболочки.

Lekensteyn
источник
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, чтобы случайно не удалить файлы, содержащие «food» (если только он не удаляет все, что содержит food, то, что вам нужно).

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

На самом деле, я бы перенаправил вывод перед удалением, чтобы я мог просмотреть перед удалением:

 $ find -type f -exec grep -q "\<foo\>" > /tmp/list_of_files_to_delete
Петтер Н
источник
Как только вы сможете оставлять комментарии, вы должны публиковать подобные комментарии.
FSMaxB
да, я сначала попробовал, но потом понял, что мне пока не разрешено оставлять комментарии.
Петтер Х