Remova todos os diretórios de um diretório pai, exceto um e seus descendentes

8

estrutura de diretórios

Quero remover os diretórios B e D. Mas quero manter C e todos os seus arquivos e diretórios descendentes. Qual é o comando para remover todos os diretórios filhos de um diretório pai, exceto um diretório e seus filhos.

Ajuda apreciada.

Joe Saad
fonte
os diretórios que você deseja remover estão vazios?
Elder Geek
E os arquivos localizados diretamente no diretório pai ( Ano seu exemplo)? Excluí-los também ou mantê-los?
Byte Commander
O que Byte Commander está perguntando é: existem arquivos em A? ou apenas diretórios? Deseja arquivos regulares em A ou apenas diretórios removidos?
Sergiy Kolodyazhnyy 29/07

Respostas:

6

O que você quer é este comando:

find ~/TESTDIR -mindepth 1 -maxdepth 1 -type d -not \( -name "keepMe" \) -exec rm -rf {} \;

Demo:

# List what's inside directory we want to remove
$ ls
file1  file2  keepMe/  removeA/  removeB/
# Testing what find gives without removing
$ find ~/TESTDIR -mindepth 1 -type d -not \( -name "keepMe" \)               
/home/xieerqi/TESTDIR/removeA
/home/xieerqi/TESTDIR/removeB
# Actual removal and testls
$ find ~/TESTDIR -mindepth 1 -maxdepth 1 -type d -not \( -name "keepMe" \) -exec rm -rf {} \;
$ ls
file1  file2  keepMe/

Explicação:

  • find DIRECTORY chamar o comando find para operar no DIRECTORY
  • -mindepth 1 : trabalhe apenas com o conteúdo do diretório, evite o próprio diretório, que é o nível 0
  • -maxdepth 1: impede a descida em subdiretórios ( rm -rfé recursivo de qualquer maneira, portanto, não precisamos descer em subdiretórios para removê-los)
  • -type d : procure apenas diretórios
  • -not \( -name "keepMe" \) ignore o item com o nome que você deseja manter
  • -exec rm -rf {} \; execute a remoção em cada item encontrado
Sergiy Kolodyazhnyy
fonte
Ótima explicação. Muitas teclas digitadas para mim ...
Elder Geek
1
findé um bom amigo aqui, mas Bash é fore testé melhor amigo ...>: - D
Byte Commander
8

Usando os recursos glob estendidos do bash shell (que são ativados por padrão nas instalações atuais do Ubuntu),

$ tree A
A
├── B
├── C
│   ├── ac1
│   └── ac2
└── D

5 directories, 0 files

você pode resolver tudo que estiver excluindo Ce seu conteúdo usando a expressão glob, A/!(C)ou seja,

$ echo A/!(C)
A/B A/D

Então, para remover tudo, exceto o diretório Ce seu conteúdo, você pode simplesmente usar

rm -rf A/!(C)

saindo

$ tree A
A
└── C
    ├── ac1
    └── ac2

3 directories, 0 files
chave de aço
fonte
É incrível saber sobre esse recurso. Ele funciona muito bem depois que eu SSH e executar manualmente, mas eu recebo ` "-bash: linha 1: erro de sintaxe próximo token inesperado ('"quando eu executá-lo remotamente via ssh $VM_ADDRESS "rm -rf $APP_FOLDER/!(node_modules)"Todas as ideias Thanks a lot.?.
Renato Gama
@renatoargh a extglobopção shell só é habilitado para shells interativos - não tenho certeza se você pode forçar ssha fazer isso
steeldriver
5

Uma maneira fácil seria usar o lixo-cli

você pode instalá-lo com sudo apt-get install trash-cli

uma vez instalado, você pode navegar para o diretório-pai A cd /Ae emitir o comando em trash B Dque B e D são os diretórios que você deseja remover (eles acabarão na lixeira da unidade em que estão), se você cometer um erro, poderá recuperar os arquivos)

Testado no Ubuntu 16.04 e 14.04

Elder Geek
fonte
Isso poderia ser simplificado com algo parecido trash ! C?
Sergiy Kolodyazhnyy 29/07
@Serg Nope trash: cannot trash non existent ! ''
Elder Geek
@Serg e C fica lixeira ...
Elder Geek
Encontre: stackoverflow.com/q/216995/3701431 Requer ativação extglob.
Sergiy Kolodyazhnyy 29/07
@Serg Dependendo do trabalho em mãos, isso pode ser bastante útil! ;-)
Elder Geek
4

Simplesmente use o forloop do Bash e testpara filtrar os diretórios desejados e o rm -rfcomando para excluir diretórios recursivamente, desta forma:

for x in /path/to/parent/*; do test "$x" != "dir_survive" && rm -rf "$x"; done

Isso itera sobre todos os elementos (arquivos e diretórios) dentro /path/to/parent/e exclui o elemento recursivamente se seu nome não for igual a dir_survive. Se o diretório pai for o diretório atual, você poderá escrever apenas *como caminho.

Se você não tiver certeza e quiser testar quais elementos serão excluídos primeiro sem executar nenhuma ação, basta substituir rm -rfo comando acima por echoe ele produzirá apenas os candidatos a exclusão.

Aqui está um exemplo de execução:

$ tree
.
├── dir1
│   ├── subdir1
│   │   ├── file1
│   │   └── file2
│   └── subdir2
│       ├── file1
│       └── file2
├── dir2
│   ├── subdir1
│   │   ├── file1
│   │   └── file2
│   └── subdir2
│       ├── file1
│       └── file2
└── dir_survive
    ├── subdir1
    │   ├── file1
    │   └── file2
    └── subdir2
        ├── file1
        └── file2

9 directories, 12 files

$ for x in *; do test "$x" != "dir_survive" && rm -rf "$x"; done

$ tree
.
└── dir_survive
    ├── subdir1
    │   ├── file1
    │   └── file2
    └── subdir2
        ├── file1
        └── file2

3 directories, 4 files
Byte Commander
fonte