it-swarm.it

Come rimuovere tutte le directory vuote in una sottostruttura?

Come posso rimuovere tutte le directory vuote in una sottostruttura? Ho usato qualcosa del genere

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

ma devo essere eseguito più volte per rimuovere solo le directory contenenti directory vuote. Inoltre, è abbastanza lento, specialmente con Cygwin.

159
maaartinus

Combinando GNU find opzioni e predicati, questo comando dovrebbe fare il lavoro:

find . -type d -empty -delete
  • -type d limita alle directory
  • -empty limita a quelli vuoti
  • -delete rimuove ogni directory

L'albero è camminato dalle foglie senza la necessità di specificare -depth come è implicito da -delete.

Elenca prima le directory profondamente annidate.

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

(Si noti che il reindirizzamento si applica al comando find nel suo insieme, non solo a rmdir. Il reindirizzamento solo per rmdir causerebbe un rallentamento significativo poiché sarebbe necessario invocare una shell intermedia).

Puoi evitare di eseguire rmdir su directory non vuote passando -empty predicato da trovare. GNU find verifica la directory quando sta per eseguire il comando, quindi verranno prese le directory che sono state appena svuotate.

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

Un altro modo per accelerare sarebbe raggruppare le invocazioni rmdir. È probabile che entrambi siano notevolmente più veloci dell'originale, specialmente con Cygwin. Non mi aspetto molta differenza tra questi due.

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

Quale metodo è più veloce dipende da quante directory non vuote hai. Non puoi combinare -empty con metodi per raggruppare le invocazioni, perché le directory che contengono solo directory vuote non sono vuote quando find le osserva.

Un altro metodo sarebbe quello di eseguire più passaggi. La maggiore rapidità dipende da molte cose, incluso se l'intera gerarchia di directory può rimanere nella cache del disco tra find esecuzioni.

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

In alternativa, usa zsh. Il qualificatore globF corrisponde a directory non vuote, quindi /^F corrisponde a directory vuote. Le directory che contengono solo directory vuote non possono essere abbinate così facilmente.

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

(Questo termina quando rmdir riceve una riga di comando vuota.)

Se hai appena virare un -p sul tuo rmdir, che funzionerà in un unico passaggio. Non sarà bello o ottimale, ma dovrebbe ottenere tutto. Ciò dice a rmdir di rimuovere tutte le directory padre non vuote di quella che stai rimuovendo.

Puoi salvare un po 'aggiungendo -empty prova a trovare, quindi non si preoccupa di directory non vuote.

6
mattdm

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

è la risposta più semplice e standard conforme a questa domanda.

Le altre risposte fornite qui purtroppo dipendono tutte da miglioramenti specifici del fornitore che non esistono su tutti i sistemi.

3
schily

Uso questi alias per i comandi find usati di frequente, specialmente quando pulisco lo spazio su disco usando dupegur, in cui la rimozione dei duplicati può provocare molte directory vuote.

Commenti all'interno di .bashrc quindi non li dimenticherò più tardi quando dovrò modificarlo.

# 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

Ecco come funziona:

  1. Elenca ricorsivamente tutte le directory insieme alla loro profondità
  2. Ordina per ordine decrescente della loro profondità
  3. Filtra solo i percorsi di directory
  4. Esegui rmdir nell'elenco uno per uno
0
Ashish Ranjan