Удалить файлы и каталоги по их именам. Данный файл или каталог отсутствует

32

Мне нужно удалить все скомпилированные данные:

  • каталоги называются build,
  • каталоги называются obj,
  • * .so файлы.

Я написал команду

find \( -name build -o -name obj -o -name *.so \) -exec rm -rf {} \;

он рекурсивно просматривает все каталоги и удаляет все, что мне нужно.

Почему у меня такой вывод в конце? Может быть, я должен написать другую команду.

find: `./3/obj': No such file or directory
find: `./3/build': No such file or directory
find: `./1/obj': No such file or directory
find: `./1/build': No such file or directory
find: `./2/obj': No such file or directory
find: `./2/build': No such file or directory
Максим Дмитриев
источник
на какой ты системе? Вы всегда должны использовать findэто, find /search_directory optionsопуская каталог поиска - не очень хорошая идея
Kiwy
Автоматическое удаление, как это плохая идея. У вас может быть сценарий, дающий вам кандидатов, который вы должны затем посмотреть, чтобы убедиться, что вы не удаляете ничего важного или необходимого для системы. Вы не ясно, где вы это запускаете. Если вы делаете это только в пользовательском пространстве, я полагаю, что это не принесет большого вреда, но вы должны убедиться, что вы случайно не делаете это в системной области. Вы определенно хотите запустить такой скрипт как пользователь.
Фахим Митха
@ Kiwy, @ FaheemMitha, команда будет использоваться только в директории проекта; это не принесет никакого вреда там.
Максим Дмитриев
Связанный: stackoverflow.com/questions/22462124/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

Ответы:

54

Используйте -pruneкаталоги, которые вы в любом случае собираетесь удалить, чтобы findне пытаться искать в них файлы:

find . \( -name build -o -name obj -o -name '*.so' \) -prune -exec rm -rf {} +

Также обратите внимание, что *.soнужно заключать в кавычки, так как в противном случае оболочка может быть расширена до списка .soфайлов в текущем каталоге.

Эквивалентом вашего -regexтипа GNU будет:

find . \( -name build -o -name obj -o -name '*?.so' \) -prune -exec rm -rf {} +

Обратите внимание, что если вы собираетесь использовать синтаксис, специфичный для GNU, вы можете использовать -deleteвместо -exec rm -rf {} +. С -delete, GNU findвключается -depthавтоматически. Он не запускает внешние команды, поэтому он более эффективен, а также безопаснее, так как устраняет условие гонки, при котором кто-то может заставить вас удалить неправильные файлы, изменив каталог между символическими ссылками в промежутке времени. findнаходит файл и rmудаляет его (см. info -f find -n 'Security Considerations for find'подробности).

find . -regextype posix-egrep -regex '.*/((obj|build)(/.*)?|.+\.so)' -delete
Стефан Шазелас
источник
-deleteтакже лучше обрабатывает такие вещи, как пробелы
Izkata
@Izkata, не лучше, чем те, -exec rm -rf {} +которые не имеют проблем с ними.
Стефан Шазелас
@StephaneChazelas - я в замешательстве {}- они должны быть процитированы или нет? Кажется, что он работает без кавычек, но GNU Findutils Manual использует '{}'в качестве примера. Не могли бы вы уточнить?
Гребнеке
1
@ grebneke, я думаю, что где-то есть пост, в котором утверждается, что цитаты могут понадобиться в очень старых версиях csh, но я никогда не смог проверить это утверждение. Они не нужны ни в одной современной оболочке, которую я знаю. Они определенно не требуются POSIX. В примерах POSIX не используют их.
Стефан Шазелас
3
И -deleteне может использоваться с каталогами.
St0rM
8

Я предполагаю, что причина в том, что findсначала удаляется дерево каталогов и пытается проверить содержимое каталога, что, очевидно, не самый лучший порядок. Вы можете findсначала проверить содержимое:

find . -depth ...

Вы должны рассмотреть возможность использования -deleteдля файлов и -exec rmdirдля каталогов.

Хауке Лагинг
источник
0

Мое решение.

find . -regextype posix-egrep -regex ".*/(obj|build|.+\.so)" -prune -exec rm -rf {} +

+ против \; в команде -exec

Максим Дмитриев
источник
Это не всегда будет работать, только если в удаленном каталоге не будет границы между выполнениями.
Жиль "ТАК - перестань быть злым"
@ Жиль, что значит «граница между казнями»?
Максим Дмитриев
1
-exec … {} +выполняет команду для нескольких файлов одновременно, столько, сколько помещается в командной строке. Если файлов слишком много (или точнее, если общая длина путей слишком велика), они findбудут выполнять несколько экземпляров rmи, следовательно, могут в конечном итоге удалить каталог, который он пересекает. Это просто менее вероятно, +чем с ;, но +не решает проблему.
Жиль "ТАК - перестань быть злым"