Видаліть порожні дерева каталогів (видаліть якомога більше каталогів, але немає файлів)


13

Припустимо, у мене є таке дерево:

ROOTDIR
    └--SUBDIR1
        └----SUBDIR2
            └----SUBDIR3

Я шукаю таку команду, що при введенні:

$ [unknown command] ROOTDIR

Це дерево dir можна видалити, якщо у файлі немає файлу, а всередині dir . Однак скажіть, чи є файл під назвою hello.pdf під SUBDIR1:

ROOTDIR
    └--SUBDIR1
        └--hello.pdf
        └----SUBDIR2
            └----SUBDIR3

Тоді команда повинна видалити лише SUBDIR2 та нижче.


Відповіді:


11

Алексіс близький. Що вам потрібно зробити, це:

find . -type d -depth -empty -exec rmdir "{}" \;

Це спочатку просверлить дерево каталогів, поки не знайде перший порожній каталог, а потім видалить його. Таким чином роблячи батьківський каталог порожнім, який потім буде видалений і т.д. Це призведе до бажаного ефекту (я роблю це, мабуть, 10 разів на тиждень, тому я впевнений, що це правильно). :-)


Чому -depthпотрібен варіант? find . -type d -empty -exec rmdir "{}" \;також повинен працювати .... правда?
Абхішек

4
Подумайте, чи є у вас дерево (лише каталоги) foo/bar/baz. Якщо ви не користуєтеся -depth, воно спробує спочатку видалити foo, вийти з ладу, і ви закінчите foo/barпісля запуску.
l0b0

1
Можливо, альтернативою є використання +замість того, ;щоб ви пакетно видаляли каталоги. Оскільки ви робите це глибоко, спочатку діти все одно будуть видалятися перед батьками (можливо, залежно від вашої версії rmdir / bash і покладається на rmdir, не видаляючи непорожні каталоги). Це працює для мене в bash на cygwin:mkdir -p a/b/c/d ; find a -depth -type d -exec rmdir {} +
idbrii

4
Люди, перейдіть за набагато більш лаконічною відповіддю go2null нижче! Не можу зрозуміти, чому ДП надає пріоритет прийнятим відповідям, а не відповідям з більшістю відгуків у відображенні відповідей нижче питання. ОП приймає найкращу відповідь, яку можна було отримати під час вибору, але згодом можуть надійти набагато кращі відповіді, які підтримує громада, ні? (Звичайно, це щось для мета ...)
jamadagni

для мене це не працює. він видаляє лише найглибший лист (SUBDIR3 в даному випадку)
Joey Baruch

24
find ROOTDIR -type d -empty -delete

такий же, як

find ROOTDIR -type d -depth -empty -exec rmdir "{}" \;

але використовує вбудовану дію "-delete".

Зауважте, що "-delete" означає "-depth".


Кудо для найкоротшого відповіді, використовуючи власну вбудовану функцію видалення! Я додаю це до своїх локальних утилітів!
jamadagni


1

Ось деякі вимоги, перш ніж ми можемо це зробити безпечно:

  1. спочатку видаліть підкаталоги, а потім каталоги верхнього рівня, тобто нам потрібно сортувати списки каталогів або використовувати прапор rmdir --parents
  2. запускайте ROOTDIR завжди з / або ./, щоб уникнути сюрпризів у файлах, що починаються з -
  3. використовувати NUL-терміновий список каталогів для роботи з іменами каталогів з пробілами

Ось як би це зробити в оболонці:

find ./ROOTDIR -type d | sort -r | tr '\n' '\000' | xargs -0 rmdir --ignore-fail-on-non-empty

Якщо ви не заперечуєте надмірних помилок, тоді ви можете просто змусити видаляти всі каталоги з батьками, і вам не потрібно робити якісь сортування (ви не можете сортувати NUL-завершені рядки, що додає потребу до tr)

find ./ROOTDIR -type d -print0 | xargs -0 rmdir --ignore-fail-on-non-empty --parents

Кудо для детального пояснення вашої відповіді. Я, певно, використовував би той самий підхід, поки не дізнався про -empty -deleteваріанти відповіді findна @ go2null.
Давор Кубраніч

0
rmdir $(find ROOTDIR -type d | sort -r)

5
Це не спрацює, якщо будь-яке ім’я каталогу містить пробіли або символи глобусу. Як правило, погана ідея використовувати заміну команд у списку імен файлів. Це особливо погана ідея з , findтому що findє спосіб зробити обробку чисто: find … -exec.
Жил 'SO- перестань бути злим'

Дякую Жиллу, що вказав на це. @lanzz, зазвичай розміщуючи лише команду, не пояснюючи, що вона робить (і в цьому випадку підводні камені) недостатньо. Будь ласка, додайте до своєї відповіді.
n0pe

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.