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

<p>как я могу удалить все пустые каталоги в поддереве? я использовал что-то вроде</p><pre><code>find . -type d -exec rmdir {} 2>/dev/null \; </code></pre><p>но мне нужно запустить несколько раз, чтобы удалить каталоги, содержащие только пустые каталоги. более того, он довольно медленный, особенно под cygwin.</p>

<p>комбинируя опции и предикаты gnu <code>find</code>), эта команда должна выполнить работу:</p><pre><code>find . -type d -empty -delete </code></pre><ul> <li><code>-type d</code> ограничивается каталогами</li> <li><code>-empty</code> ограничивается пустыми</li> <li><code>-delete</code> удаляет каждый каталог</li> </ul><p>дерево отходит от листьев без необходимости указывать <code>-depth</code> как подразумевается <code>-delete</code>.</p>

<p>перечислите каталоги, глубоко вложенные в первую очередь.</p><pre><code>find . -depth -type d -exec rmdir {} \; 2>/dev/null </code></pre><p>(обратите внимание, что перенаправление применяется к команде <code>find</code> в целом, а не только к <code>rmdir</code>. перенаправление только для <code>rmdir</code> приведет к значительному замедлению, так как вам придется вызывать промежуточная оболочка.)</p><p>вы можете избежать запуска <code>rmdir</code> в непустых каталогах, передав <code>-empty</code> предикат, чтобы найти. gnu find проверяет каталог, когда он собирается выполнить команду, поэтому каталоги, которые только что были очищены, будут выбраны.</p><pre><code>find . -depth -type d -empty -exec rmdir {} \; </code></pre><p>другой способ ускорить работу - сгруппировать вызовы <code>rmdir</code>. оба, вероятно, будут заметно быстрее, чем оригинал, особенно при cygwin. я не ожидаю большой разницы между этими двумя.</p><pre><code>find . -depth -type d -print0 | xargs -0 rmdir 2>/dev/null find . -depth -type d -exec rmdir {} + 2>/dev/null </code></pre><p>какой метод быстрее, зависит от того, сколько у вас непустых каталогов. вы не можете объединить <code>-empty</code> с методами группировки вызовов, потому что тогда каталоги, которые содержат только пустые каталоги, не будут пустыми к тому времени, когда <code>find</code> просматривает их.</p><p>другим способом было бы запустить несколько проходов. быстрее ли это, зависит от многих вещей, в том числе от того, может ли вся иерархия каталогов оставаться в дисковом кэше между запусками <code>find</code>.</p><pre><code>while [ -n "$(find . -depth -type d -empty -print -exec rmdir {} +)" ]; do :; done или используйте zsh. <a href="http://zsh.sourceforge.net/doc/release/expansion.html#glob-qualifiers">квалификатор glob f соответствует непустым каталогам, поэтому /^f соответствует пустым каталогам. каталоги, которые содержат только пустые каталоги, не могут быть сопоставлены так легко.while rmdir /(/n^f); do :; done (это заканчивается, когда rmdir получает пустую командную строку.)

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

find . -depth -type d -exec rmdir {} +это самый простой и стандартный ответ на этот вопрос.другие ответы, приведенные здесь, к сожалению, все зависят от конкретных улучшений, которые существуют не во всех системах.

я использую эти псевдонимы для часто используемых команд find, особенно когда я очищаю дисковое пространство с помощью dupegur, где удаление дубликатов может привести к большому количеству пустых каталогов.комментарии внутри .bashrc так что я не забуду их позже, когда мне нужно настроить это.<pre class="lang-bsh prettyprint-override"># 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 {} +' 

find . -type d -printf "%d %pn" | sort -nr | perl -pe 's/^d+s//;' | while read dir; do  (rmdir "$dir" > /dev/null 2>&1); \ done</code></p><p>вот как это работает:</p><ol> <li>рекурсивно перечислите все каталоги вместе с их глубиной</li> <li>сортировать по убыванию их глубины</li> <li>отфильтровать только пути к каталогам</li> <li>запустите <code>rmdir</code> в списке один за другим</li> </ol>