TL; DR: найкращим способом є використання -exec rm
замість -delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
Пояснення:
Чому знайти скаржаться , коли ви намагаєтеся використовувати -delete
з -prune
?
Коротка відповідь: тому що це -delete
означає -depth
і -depth
робить -prune
неефективним.
Перш ніж ми прийдемо до довгої відповіді, спочатку спостерігайте за поведінкою знахідки з і без -depth
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
Немає гарантій щодо замовлення в одному каталозі. Але є гарантія, що каталог буде оброблений перед його вмістом. Зверніть увагу foo/
перед будь-яким foo/*
і foo/bar
перед будь-яким foo/bar/*
.
Це можна змінити за допомогою -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Зверніть увагу, що зараз всі foo/*
з'являються раніше foo/
. Те саме з foo/bar
.
Більш довга відповідь:
-prune
запобігає спуску в каталог. Іншими словами -prune
пропускає вміст каталогу. У вашому випадку -name b -prune
не дозволяє знайти спуск у будь-який каталог з назвою b
.
-depth
змушує обробляти вміст каталогу перед самим каталогом. Це означає, що до моменту, коли знахідка обробляє запис каталогу, b
його вміст уже оброблений. Таким чином, -prune
це неефективно з -depth
дією.
-delete
Мається на увазі, -depth
щоб він міг видалити файли спочатку, а потім порожній каталог. -delete
відмовляється видаляти непорожні каталоги. Я здогадуюсь, можна було б додати опцію, щоб примусити -delete
видаляти непорожні каталоги та / або запобігти -delete
натяк -depth
. Але це вже інша історія.
Є ще один спосіб досягти того, що ви хочете:
find a -not -path "*/b*" -type f -delete
Це може бути, а може і не простіше запам'ятати.
Ця команда все ще спускається до каталогу b
та обробляє кожен файл у ній лише для того, -not
щоб їх відхилити. Це може бути проблемою з продуктивністю, якщо каталог b
величезний.
-path
працює інакше, ніж -name
. -name
збігається лише з ім'ям (файлу чи каталогу), тоді -path
як відповідає всім шляхом. Наприклад, спостерігайте за стежкою /home/lesmana/foo/bar
. -name -bar
відповідатиме тому, що ім’я є bar
. -path "*/foo*"
відповідатиме тому, що рядок /foo
стоїть на шляху. -path
має деякі тонкощі, які слід розібратися, перш ніж використовувати його. Прочитайте сторінку людини find
для отримання більш детальної інформації.
Слідкуйте за тим, щоб це не на 100% надійне. Є шанси на "помилкові позитиви". Як команда написана вище, вона пропустить будь-який файл, у якому є будь-яка батьківська директорія, з імені якої починається b
(позитивно). Але він також пропустить будь-який файл, ім'я якого починається з b
незалежно від позиції в дереві (хибнопозитивний). Це можна виправити, написавши кращий вираз, ніж "*/b*"
. Це залишається як вправа для читача.
Я припускаю, що ви використовували a
і b
як заповнювачі, і справжні імена, як allosaurus
і brachiosaurus
. Якщо поставити brachiosaurus
на місце, b
то кількість помилкових позитивних результатів буде різко зменшена.
По крайней мере, помилкові спрацьовування будуть НЕ видалені, так що це буде не так трагічно. Крім того, ви можете перевірити помилкові позитиви, спершу запустивши команду без -delete
(але пам'ятайте, що розміщується мається на увазі -depth
) та вивчити вихід.
find a -not -path "*/b*" -type f -depth
a
крімa/b
?