Ответ 1
Следующее будет работать:
find . -type f -print0 | xargs --null grep -Z -L 'my string' | xargs --null rm
Это сначала использует find для печати имен всех файлов в текущем каталоге и любых подкаталогах. Эти имена печатаются с нулевым терминатором, а не с обычным разделителем строк (попробуйте подключить вывод к od -c
, чтобы увидеть эффект аргумента -print0
.
Затем параметр --null
в xargs
сообщает ему принимать входы с нулевым завершением. xargs
затем вызовет grep
в списке имен файлов.
Аргумент -Z
для grep
работает как -print0
аргумент find
, поэтому grep будет распечатывать его результаты с нулевым завершением (поэтому для окончательного вызова xargs
требуется --null
вариант тоже). Аргумент -L
для grep
заставляет grep
печатать имена файлов этих файлов в его командной строке (добавлен xargs
), которые не соответствуют соответствуют регулярному выражению: p >
моя строка
Если вам нужно простое совпадение без магии регулярного выражения, добавьте параметр -F
. Если вам нужны более мощные регулярные выражения, дайте аргумент -E
. Это хорошая привычка использовать одинарные кавычки, а не двойные кавычки, так как это защищает вас от любой магии оболочки, применяемой к строке (например, подстановки переменных).
Наконец, вы вызываете xargs
снова, чтобы избавиться от всех файлов, которые вы нашли с предыдущими вызовами.
Проблема с вызовом grep
непосредственно из команды find
с аргументом -exec
заключается в том, что grep
затем запускается один раз для каждого файла, а не один раз для цельной партии файлов, как это делает xargs
. Это намного быстрее, если у вас много файлов. Также не поддавайтесь соблазну делать такие вещи, как:
rm $(some command that produces lots of filenames)
Всегда лучше передать его на xargs
, поскольку он знает максимальные пределы командной строки и будет вызывать rm
несколько раз каждый раз с таким количеством аргументов, сколько он может.
Обратите внимание, что это решение было бы проще, без необходимости справляться с файлами, содержащими пробелы и новые строки.
В качестве альтернативы
grep -r -L -Z 'my string' . | xargs --null rm
тоже будет работать (и короче). Аргумент -r
для grep
заставляет его читать все файлы в каталоге и рекурсивно спускаться в любые подкаталоги). Используйте подход find ...
, если вы хотите также выполнить некоторые другие тесты в файлах (например, возраст или разрешения).
Обратите внимание, что любой из однобуквенных аргументов с одним указателем штриховки может быть сгруппирован (например, как -rLZ
). Но обратите внимание также, что find
не использует те же соглашения и имеет многобуквенные аргументы, введенные с одной тире. Это по историческим причинам и никогда не было исправлено, потому что это сломало бы слишком много скриптов.