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

20

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

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

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

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

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

Otheus
источник
4
Ой ... Я кое-что узнал сегодня (спасибо тебе). И я рекомендую сделать простую mv save/ ../some/safer/locationдо такой «универсальной» команды удаления (... но, конечно, до вашего поста я бы сделал такую ​​же проверку и столкнулся с той же проблемой!). Теперь найдите хорошего «восстановителя» для файловой системы, в которой были файлы ^^
Оливье Дюлак
3
Моя боль - твоя профилактика.
Отей
1
1000 благодаря вам. Код (часто?) Работает таинственным образом ...
Оливье Дюлак
3
связанные: unix.stackexchange.com/questions/87258/…
lesmana
@lesmana Я проголосовал за твой ответ там. к сожалению, моя версия find не дает мне такого приятного предупреждения :(
Otheus

Ответы:

26

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

info find --index-search=-delete

Использование действия «-delete» в командной строке автоматически включает параметр «-depth» (* обратите внимание, найти выражения: :). Это может удивить, если вы ранее просто тестировали с помощью «-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на файл. --Необходимо для реализации FreeBSD, а не GNU один , что имена файлов префиксы с ./.

В качестве альтернативы, как предложил Костас:

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

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

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

Стефан Шазелас
источник
С чем здесь проблема безопасности rm?
jrw32982 поддерживает Монику
@ jrw32982, см. редактирование со ссылкой на руководство по поиску в GNU
Стефан Шазелас