Почему find с -delete удаляет файлы в каталоге / save /, когда find без удаления не смог найти их?

Я хочу удалить все файлы в текущем дереве каталогов, кроме тех, которые save . Я выполнил эту команду:

  find . \( -name save -prune \) -o -type f -ls | grep /save/ 

и он не нашел ни одного. Но когда я выполнил эту команду:

  find . \( -name save -prune \) -o -type f -delete 

Все эти файлы в / save / ушли. Что мне не хватает?

-delete означает -depth , который не работает с -prune ( -depth начинается с листьев). Предупреждение об этом содержится в руководстве по версии GNU ( -delete – это расширение GNU, которое также поддерживается приложением FreeBSD).

 info find --index-search=-delete 

Использование действия «-delete» в командной строке автоматически включает параметр «-depth» (* note find expression: :). Это может быть неожиданным, если вы раньше просто тестировали «-print», поэтому обычно лучше не использовать «-depth» явно.

 info find --index-search=-prune 

Поскольку «-delete» подразумевает «-depth», использование «-prune» в сочетании с «-delete» вполне может привести к удалению большего количества файлов, чем вы планировали.

Здесь у вас есть возможность использовать rm вместо:

 find . -name save -prune -o -type f -exec rm -f {} + 

(потенциально небезопасно, если есть каталог, который можно записать другими пользователями там, так как вы можете удалить файлы за пределами текущего дерева каталогов, заменив каталоги символическими ссылками во время выполнения этой команды).

Более безопасная альтернатива:

 find . -name save -prune -o -type f -execdir rm -f -- {} \; 

Это не проблема, упомянутая выше, но означает, что она работает на один rm за файл. The -- необходим для реализации FreeBSD, а не для GNU, который префикс имен файлов с ./ .

Как вариант, предложенный Костасом:

 LC_ALL=C find . ! -name save ! -path '*/save/*' -type f -delete 

(но это все же бесполезно спускается в каталоги save )

LC_ALL=C поэтому * соответствует любой последовательности байтов (даже тех, которые не образуют действительных символов в текущей локали). Обратите внимание, что это повлияет на язык сообщений об ошибках (на английском языке вместо языка пользователя).