Remova as árvores de diretórios vazias (removendo o máximo de diretórios possível, mas nenhum arquivo)


12

Suponha que eu tenha uma árvore de diretório como esta:

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

Estou procurando um comando que, quando eu insiro:

$ [unknown command] ROOTDIR

A árvore de diretórios inteira pode ser excluída se não houver arquivo, mas somente dirs dentro da árvore inteira . No entanto, diga se existe um arquivo chamado hello.pdf em SUBDIR1:

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

Em seguida, o comando deve excluir apenas SUBDIR2 e abaixo.


Respostas:


11

Alexis está perto. O que você precisa fazer é o seguinte:

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

Isso fará uma busca detalhada na árvore de diretórios até encontrar o primeiro diretório vazio e, em seguida, exclua-o. Assim, deixando o diretório pai vazio, que será excluído etc. Isso produzirá o efeito desejado (eu faço isso provavelmente 10 vezes por semana, por isso tenho certeza de que está certo). :-)


Por que a -depthopção é necessária? find . -type d -empty -exec rmdir "{}" \;também deve funcionar .... certo?
Abhishek Um

4
Considere se você tem uma árvore (somente diretórios) foo/bar/baz. A menos que você use -depth, ele tentará excluir fooprimeiro, falhar e você terminará foo/barapós a execução.
L0b0

1
Possivelmente alternativa é usar em +vez de ;remover remotamente os diretórios. Como você está fazendo isso primeiro, os filhos ainda serão removidos antes dos pais (possivelmente dependente da sua versão do rmdir / bash e dependente do rmdir não excluir diretórios não vazios). Isso funciona para mim no bash no cygwin:mkdir -p a/b/c/d ; find a -depth -type d -exec rmdir {} +
idbrii

3
Gente, vá para a resposta muito mais sucinta do go2null abaixo! Não consigo entender por que o SE dá prioridade às respostas aceitas, em vez das respostas com mais votos positivos na exibição das respostas abaixo da pergunta. O OP aceita a melhor resposta disponível no momento de sua escolha, mas mais tarde poderão surgir respostas muito melhores que a comunidade votará, não? (Claro, isso é algo para meta ...)
Jamadagni

isso não funciona para mim. mas são excluídos da folha deepmost (SUBDIR3 neste caso)
Baruch Joey

23
find ROOTDIR -type d -empty -delete

igual a

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

mas usa a ação "-delete" incorporada.

Observe que "-delete" implica "-pth".


Parabéns pela resposta mais sucinta, usando a exclusão interna do find! Estou adicionando isso aos meus utilscripts locais!
Jamadagni

3

Eu tentaria o seguinte:

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

1

Aqui estão alguns requisitos antes de podermos fazer isso com segurança:

  1. remova primeiro os subdiretórios e depois os diretórios de nível superior, ou seja, precisamos classificar a listagem de diretórios ou usar rmdir --parents flag
  2. inicie o ROOTDIR sempre com / ou ./ para evitar surpresas com arquivos começando com -
  3. use lista de diretórios terminada em NUL para trabalhar com nomes de diretórios com espaços

Aqui está como eu faria isso no shell:

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

Se você não se importa com alguns erros redundantes, basta forçar a remoção de todos os diretórios com os pais e não precisa fazer nenhuma classificação (você não pode classificar cadeias terminadas NUL, o que adiciona necessidade de tr)

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

Parabéns pela explicação detalhada da sua resposta. Eu provavelmente teria usado a mesma abordagem, até aprender sobre as -empty -deleteopções findda resposta do @ go2null.
Davor Cubranic

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

5
Isso não funcionará se qualquer um dos nomes de diretório contiver caracteres em branco ou em branco. Geralmente, é uma má idéia usar a substituição de comandos em uma lista de nomes de arquivos. É especialmente uma má idéia com findporque findtem uma maneira de fazer o processamento de forma limpa: find … -exec.
Gilles 'SO- stop be evil'

Obrigado a Gilles por apontar isso. @lanzz, normalmente postar apenas um comando sem explicar o que ele faz (e, neste caso, as armadilhas) não é suficiente. Por favor, adicione a sua resposta.
N0pe 8/11/11

0

Eu faria o seguinte:

find ROOTDIR -type d | xargs -0 -I {} rmdir {}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.