it-swarm-ru.tech

Как удалить все пустые каталоги в поддереве?

Как я могу удалить все пустые каталоги в поддереве? Я использовал что-то вроде

find . -type d -exec rmdir {} 2>/dev/null \;

но мне нужно запустить несколько раз, чтобы удалить каталоги, содержащие только пустые каталоги. Более того, он довольно медленный, особенно под Cygwin.

159
maaartinus

Комбинируя опции и предикаты GNU find), эта команда должна выполнить работу:

find . -type d -empty -delete
  • -type d ограничивается каталогами
  • -empty ограничивается пустыми
  • -delete удаляет каждый каталог

Дерево отходит от листьев без необходимости указывать -depth как подразумевается -delete.

237
Christophe Drevet-Droguet

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

find . -depth -type d -exec rmdir {} \; 2>/dev/null

(Обратите внимание, что перенаправление применяется к команде find в целом, а не только к rmdir. Перенаправление только для rmdir приведет к значительному замедлению, так как вам придется вызывать промежуточная оболочка.)

Вы можете избежать запуска rmdir в непустых каталогах, передав -empty предикат, чтобы найти. GNU find проверяет каталог, когда он собирается выполнить команду, поэтому каталоги, которые только что были очищены, будут выбраны.

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

Другой способ ускорить работу - сгруппировать вызовы rmdir. Оба, вероятно, будут заметно быстрее, чем оригинал, особенно при Cygwin. Я не ожидаю большой разницы между этими двумя.

find . -depth -type d -print0 | xargs -0 rmdir 2>/dev/null
find . -depth -type d -exec rmdir {} + 2>/dev/null

Какой метод быстрее, зависит от того, сколько у вас непустых каталогов. Вы не можете объединить -empty с методами группировки вызовов, потому что тогда каталоги, которые содержат только пустые каталоги, не будут пустыми к тому времени, когда find просматривает их.

Другим способом было бы запустить несколько проходов. Быстрее ли это, зависит от многих вещей, в том числе от того, может ли вся иерархия каталогов оставаться в дисковом кэше между запусками find.

while [ -n "$(find . -depth -type d -empty -print -exec rmdir {} +)" ]; do :; done

Или используйте zsh. квалификатор globF соответствует непустым каталогам, поэтому /^F соответствует пустым каталогам. Каталоги, которые содержат только пустые каталоги, не могут быть сопоставлены так легко.

while rmdir **/*(/N^F); do :; done

(Это заканчивается, когда rmdir получает пустую командную строку.)

53

Если вы просто прикрепите -p на вашем rmdir, это сработает за один проход. Он не будет красивым или оптимальным, но он должен получить все. Это говорит rmdir об удалении любых непустых родительских каталогов той, которую вы удаляете.

Вы можете немного сэкономить, добавив -empty проверить, чтобы найти, чтобы он не беспокоился о непустых каталогах.

6
mattdm

find . -depth -type d -exec rmdir {} +

это самый простой и стандартный ответ на этот вопрос.

Другие ответы, приведенные здесь, к сожалению, все зависят от конкретных улучшений, которые существуют не во всех системах.

3
schily

Я использую эти псевдонимы для часто используемых команд find, особенно когда я очищаю дисковое пространство с помощью dupegur, где удаление дубликатов может привести к большому количеству пустых каталогов.

Комментарии внутри .bashrc так что я не забуду их позже, когда мне нужно настроить это.

# find empty directories
alias find-empty='find . -type d -empty'

# fine empty/zero sized files
alias find-zero='find . -type f -empty'

# delete all empty directories!
alias find-empty-delete='find-empty -delete'

# delete empty directories when `-delete` option is not available.
# output null character (instead of newline) as separator. used together
# with `xargs -0`, will handle filenames with spaces and special chars.
alias find-empty-delete2='find-empty -print0 | xargs -0 rmdir -p'

# alternative version using `-exec` with `+`, similar to xargs.
# {}: path of current file
# +: {} is replaced with as many pathnames as possible for each invocation.
alias find-empty-delete3='find-empty -exec rmdir -p {} +'

# for removing zero sized files, we can't de-dupe them automatically
# since they are technically all the same, so they are typically left
# beind. this removes them if needed.
alias  find-zero-delete='find-zero -delete'
alias find-zero-delete2='find-zero -print0 | xargs -0 rm'
alias find-zero-delete3='find-zero -exec rm {} +'
0
raychi

find . -type d -printf "%d %p\n" |\ sort -nr |\ Perl -pe 's/^\d+\s//;' |\ while read dir; do \ (rmdir "$dir" > /dev/null 2>&1); \ done

Вот как это работает:

  1. Рекурсивно перечислите все каталоги вместе с их глубиной
  2. Сортировать по убыванию их глубины
  3. Отфильтровать только пути к каталогам
  4. Запустите rmdir в списке один за другим
0
Ashish Ranjan