Como faço para remover todos os subdiretórios de um diretório?

51

Esta pergunta é como uma fase II da primeira pergunta que publiquei aqui

Eu tenho um diretório que contém um monte de subdiretórios, arquivos .zip e outros arquivos aleatórios não contidos em um subdiretório.

Gostaria de um script de linha de comando para remover todos os subdiretórios do diretório pai, mas manter todos os arquivos zip e arquivos soltos que não pertencem a nenhum subdiretório. Todos os subdiretórios têm conteúdo, então acredito que precisaria forçar a exclusão deles com o comando -f.

Então, basicamente, um comando que olha dentro do diretório pai (ou diretório atual) exclui todas as pastas de dentro dele, mas mantém todos os outros conteúdos e arquivos que não são uma pasta ou contidos em uma pasta.

Entendo que a exclusão de itens da linha de comando requer cuidados especiais, mas já tomei todas as precauções necessárias para fazer backup remotamente.

Evster
fonte

Respostas:

62

No BASH, você pode usar a barra final ( acho que deve funcionar em qualquer shell POSIX):

rm -R -- */

Observe o --que separa as opções dos argumentos e permite remover entradas começando com um hífen - caso contrário, após a expansão pelo shell, o nome da entrada seria interpretado como uma opção por rm(o mesmo vale para muitos outros utilitários de linha de comando).

Adicione a -fopção se você não deseja que seja solicitada confirmação ao excluir arquivos não graváveis.

Observe que, por padrão, os diretórios ocultos (aqueles cujo nome começa .) serão deixados em paz.

Uma ressalva importante: a expansão de */também incluirá links simbólicos que acabam sendo resolvidos para arquivos do tipo diretório . E, dependendo da rmimplementação, rm -R -- thelink/apenas excluirá o link simbólico ou (na maioria deles) excluirá o conteúdo do diretório vinculado recursivamente, mas não o diretório em si nem o link simbólico.

Se estiver usando zsh, uma abordagem melhor seria usar um qualificador global para selecionar apenas arquivos do tipo diretório:

rm -R -- *(/) # or *(D/) to include hidden ones

ou:

rm -R -- *(-/)

para incluir links simbólicos para diretórios (mas, dessa vez, a expansão não possui /s à direita , é o link simbólico que é removido apenas com todas as rmimplementações).

Com bash, AT & T ksh, yashou zshvocê pode fazer:

set -- */
rm -R -- "${@%/}"

para tirar a trilha /.

peterph
fonte
Bela! Isso funciona perfeitamente. Eu não sabia que era tão fácil de fazer. Você se importaria de elaborar sobre -r vs. -R e o que esses comandos fazem? Muito Obrigado.
Evster 22/03
-r, -R, --recursiveSão sinônimos que significa "diretórios remover e seus conteúdos de forma recursiva".
Peterph
você pode explicar o que - e * / fazer?
amphibient
6
Você também pode dizer rm -R ./*/- Isso também evita problemas com nomes de hífen.
L0b0 23/03
11
Apenas tome cuidado para não alterar a ordem do * e do /. rm -R - / * faz algo totalmente diferente que você pode não querer que aconteça: |
21418 ChrisOdney
13

Além da forma curinga, você também pode usar find(pelo menos a localização do GNU) para fazer isso:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 rm -R

Como em outras findlinhas, você pode executar a primeira parte ( find -mindepth 1 -maxdepth 1 -type d) para ver uma lista de diretórios que serão removidos.

Uma opção mais segura é fazer algo assim:

find -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 mv -i -t ../to-rm
# or
mv -i -t ../to-rm */
# or
mv -i */ ../to-rm

qualquer um dos quais moverá todo o material para em ../to-rmvez de excluí-lo. Você pode verificar se fez o que queria, rm -Rfo diretório que quiser.

derobert
fonte
+1 para a "Lixeira da CLI" to-rme findque lida com diretórios com bom gosto começando com um ponto (além de qualquer outro escape complicado). :)
peterph
Obrigado pela dica. Eu gosto da ideia de mudar para um diretório separado antes de excluir. Estou trabalhando no Terminal no Mac OS X e acredito que precisaria instalar algum tipo de pacote GNU para usar os comandos -mindepth e -maxdepth, correto?
Evster 22/03
@ Evster não tem certeza se o Mac OS X find é compatível. Eu acho que o fink (isso ainda existe?) Poderia instalar uma descoberta que sim. Ou você pode omiti-los e filtrar a lista de arquivos produzidos usando grep. Definitivamente, use a opção mv, em vez de rm.
Derobert
4

Você pode criar um script para algumas dessas sugestões, especialmente rm -R -- */, e mantê-lo na sua pasta / usr / local / bin; ou crie um aliasno seu arquivo ~ / .bashrc. Como é muito fácil digitar um comando incorretamente e quebrar seu sistema - mesmo uma única letra e / ou a ordem das letras podem resultar em consequências catastróficas - isso serviria como uma solução um pouco mais robusta do que ter que digitar as diferentes opções e argumentos cada vez que você deseja realizar esta tarefa.

Além disso, convém incluir a opção -i or --interactive=onceou -I or --interactive=alwaysem seu script / comando, que servirá como outra ferramenta para evitar exclusões não intencionais.

Além disso, algo como derobert sugerido seria o melhor; basta copiar / colar o script em um arquivo / editor de terminal e ajustá-lo às suas necessidades específicas, e os arquivos / diretórios serão movidos para um único diretório (cujo conteúdo você pode verificar / verificar) que você pode simplesmente remover emitindo o rm -rfcomando.

Outra opção é usar um aplicativo GUI, como o gerenciador de arquivos, e simplesmente selecionar todos os arquivos / pastas aplicáveis ​​que você deseja excluir. Verifique as páginas de manual da sua distribuição se você não tiver permissões.

Por fim, se as pastas estiverem vazias - nomes de arquivos essencialmente simples - você pode usar o rmdircomando para excluí-las. Não funciona para tudo o que você deseja excluir, mas será útil às vezes em que você desejar fazer uma "limpeza doméstica". ** Você pode tentar a -p --ignore-fail-on-non-emptyopção, que permitirá excluir determinados subdiretórios, bem como seus "pais" vazios - os diretórios nos quais eles residem.

ILMostro_7
fonte
Essa é realmente uma boa ideia sobre a criação de um script separado que eu posso chamar para esse comando. Você pode explicar o que exatamente as opções -i e -I fazem? Obrigado!
Evster 23/03
-I opção solicitará uma vez depois que você pressionar "Enter" para confirmar que deseja remover isso (quando houver mais de 3 arquivos / pastas "selecionados"); enquanto a opção -i emitirá um prompt para cada arquivo, no qual você pode simplesmente confirmar pressionando "y" e "Enter" - qualquer coisa além de uma resposta afirmativa fará com que o arquivo específico seja ignorado durante o processo de remoção.
ILMostro_7 23/03
1

Primeiro, você precisa listar os diretórios e depois removê-los, sem prejudicar os arquivos normais, ls -d * /, lista apenas os subdiretórios, e canalizar com rm remove os diretórios e o conteúdo, mantendo intactos os arquivos soltos.

Este comando deve fazer o trabalho,

ls -d  */ | xargs rm -rf
Ankit Marothi
fonte
11
Qual seria o benefício rm -rf -- */? printf '%s\0' */ | xargs -r0 rm -rf --ajudaria (em shells onde printfestá embutido e não ls) a solucionar erros muito grandes da lista arg , mas ls -d */ | xargs rm -rfnão adiciona nada AFAICT, exceto problemas adicionais.
Stéphane Chazelas
11
@AnthonyGeoghegan, sim, por exemplo, se houvesse um diretório chamado " .."(espaço ..), ele removeria o conteúdo do diretório pai com algumas lsimplementações. E não se trata apenas de espaços, mas também de outros caracteres em branco, nova linha, aspas simples, aspas duplas, barra invertida e nomes de arquivos -.
Stéphane Chazelas
2
@Ankit, você pode começar com mywiki.wooledge.org/ParsingLs
Stéphane Chazelas
11
Quando você entender completamente a sugestão de @ StéphaneChazelas de usar printfpara gerar uma lista em que cada nome é encerrado pelo caractere nulo para que possa ser processado xargscom a -0opção, aconselho que você edite sua resposta para atualizá-la com a variação dele. Eu ficaria bastante confiante de que ele ficaria feliz em você usar o snippet de código dele, se você o entender e aprender como ele protege contra comportamentos indesejáveis ​​causados ​​por determinados nomes de arquivos que poderiam existir.
Anthony G - justice for Monica
11
O uso xargstem uma vantagem sobre a resposta aceita (funciona quando há um número muito grande de arquivos / diretórios no diretório atual), portanto há espaço para editar isso em uma resposta útil. Pessoalmente, achei que responder às perguntas do Stack Exchange é uma boa experiência de aprendizado - principalmente quando recebo feedback útil de outros usuários.
Anthony G - justice for Monica
-1

rm -rf <directory name>. Funciona. Basta digitar rm <directory name>apenas leva a um número de subperguntas nas quais cada subdiretório deve ser removido manualmente. Mas, rm -rfajuda a remover o diretório inteiro junto com seus subdiretórios de uma só vez.

Riya Melvin
fonte
5
O OP pediu para manter o conteúdo do diretório atual.
Stephen Rauch