Exclui todas as pastas dentro de uma pasta, exceto uma com nome específico

7

Eu preciso excluir todas as pastas dentro de uma pasta usando um script diário. A pasta desse dia precisa ser deixada.

A pasta 'myfolder' tem 3 subpastas: 'test1', 'test2' e 'test3' Preciso excluir todos, exceto 'test2'.

Estou tentando corresponder o nome exato aqui:

find /home/myfolder -type d ! -name 'test2' | xargs rm -rf

OR

find /home/myfolder -type d ! -name 'test2' -delete

Este comando sempre tenta excluir a pasta principal 'myfolder' também! Há alguma maneira de evitar isto ?

    
por Riju Mahna 06.02.2018 / 21:59

5 respostas

19

Isso excluirá todas as pastas dentro de ./myfolder , exceto que ./myfolder/test2 e todo o seu conteúdo será preservado:

find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?' -delete

Como funciona

  • find inicia um comando de localização.
  • ./myfolder informa ao find para começar com o diretório ./myfolder e seu conteúdo.

  • -mindepth 1 não corresponde a ./myfolder em si, apenas os arquivos e diretórios sob ele.

  • ! -regex '^./myfolder/test2\(/.*\)?' informa ao find para excluir ( ! ) qualquer arquivo ou diretório correspondente à expressão regular ^./myfolder/test2\(/.*\)? . ^ corresponde ao início do nome do caminho. A expressão (/.*\)? corresponde a (a) uma barra seguida por qualquer coisa ou (b) nada.

  • -delete informa ao Google para excluir os arquivos correspondentes (ou seja, não excluídos).

Exemplo

Considere uma estrutura de diretório semelhante a essa:

$ find ./myfolder
./myfolder
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2

Podemos executar o comando find (sem -delete ) para ver o que corresponde:

$ find ./myfolder -mindepth 1 ! -regex '^./myfolder/test2\(/.*\)?'
./myfolder/test1
./myfolder/test1/dir1
./myfolder/test1/dir1/test2
./myfolder/test1/dir1/test2/file4
./myfolder/test1/file1
./myfolder/test3
./myfolder/test3/file3

Podemos verificar se isso funcionou observando os arquivos que permanecem:

$ find ./myfolder
./myfolder
./myfolder/test2
./myfolder/test2/file2
./myfolder/test2/dir2
    
por 06.02.2018 / 22:03
10

Usando o bash :

shopt -s extglob
rm -r myfolder/!(test2)/

Exemplo:

$ tree myfolder/
myfolder/
├── test1
│   └── file1
├── test2
│   └── file2
└── test3
    └── file3

$ echo rm -r myfolder/!(test2)
rm -r myfolder/test1 myfolder/test3
$ rm -r myfolder/!(test2)
$ tree myfolder/
myfolder/
└── test2
    └── file2

1 directory, 1 file
    
por 06.02.2018 / 22:11
4

tl; dr

find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 \
     -exec echo rm -rf '{}' \;

Remova o eco se estiver satisfeito com a lista de arquivos.

Usar -mindepth 1 garantirá que o diretório top não esteja selecionado.

$ find ./myfolder -mindepth 1 -type d
./myfolder/test2
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Mas um -not -name test2 não irá não evitar subdiretórios dentro de test2 :

$ find ./myfolder -mindepth 1 -type d -not -name 'test2'
./myfolder/test2/one
./myfolder/test2/two
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Para fazer isso, você precisa de algo como podar:

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test
./myfolder/test/a1
./myfolder/test/a1/a2
./myfolder/test/a1/a2/a3

Mas não use delete , pois isso implica em depth e isso começará a ser apagado do caminho mais longo:

$ find ./myfolder -depth -mindepth 1 -name test2 -prune -o -type d -print
./myfolder/test/a1/a2/a3
./myfolder/test/a1/a2
./myfolder/test/a1
./myfolder/test

Use rm -rf (remova o echo se você quiser realmente apagar):

$ find ./myfolder -mindepth 1 -name test2 -prune -o -type d -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test
rm -rf ./myfolder/test/a1
rm -rf ./myfolder/test/a1/a2
rm -rf ./myfolder/test/a1/a2/a3

Ou, também use maxdepth se tudo que você precisa é excluir diretórios (e tudo dentro) (remova o echo para realmente apagar):

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -exec echo rm -rf '{}' \;
rm -rf ./myfolder/test

Um -delete ainda falhará se o diretório não estiver vazio:

$ find ./myfolder -mindepth 1 -maxdepth 1 -type d -not -name test2 -delete
find: cannot delete ‘./myfolder/test’: Directory not empty
    
por 06.02.2018 / 22:28
2

Se você estiver usando zsh, poderá:

setopt extended_glob # if you don't have it enabled

rm -rf myfolder/^test2
    
por 07.02.2018 / 01:05
0

Testado com o comando abaixo e funcionou bem

find  /home/myfolder -maxdepth 1 -type d ! -iname test2 -exec rm -rvf {} \;
    
por 07.11.2018 / 16:40