Use find para encontrar determinado diretório e excluir todos os arquivos nele, exceto um diretório

5

Estou tendo o seguinte problema. Eu tenho uma estrutura de diretório e quero excluir tudo o que está dentro de um diretório chamado Caches . Tudo deve ser excluído, exceto todos os diretórios denominados Snapshots . Eu não consigo descobrir como fazer isso com find ou qualquer outro comando que eu conheça.

A razão pela qual estou perguntando: no iOS, cada aplicativo tem seu próprio diretório de Caches. Estes, por vezes, não são limpos corretamente, dependendo do aplicativo. Com a solução para essa resposta, seria possível limpar o Caches no iOS e, portanto, otimizar o espaço em disco, quando a unidade dos dispositivos é montada em outro computador, por exemplo, com FUSE (iExplorer).

Isso é o que eu tenho até agora:

find . 2>/dev/null -type d -name "Caches" -maxdepth 3 -print

Isso retorna algo como:

./Library/Caches

Quando faço um ls ./Library/Caches , vejo todo o conteúdo e o diretório Snapshots , que desejo excluir porque, em última instância, quero -delete , exceto este.

Eu quero algo assim:

  Before:                            After:

  .                                  .
  ├── a                              ├── a
  │   ├── a                          │   ├── a
  │   └── Caches                     │   └── Caches
  │       ├── a                      │       └── a
  │       │   └── Snapshots          │           └── Snapshots
  │       │       └── a              │               └── a
  │       ├── b                      └── b
  │       │   └── a                      └── c
  │       └── c                  
  └── b
      ├── c
      └── Caches
          ├── a
          │   └── foo
          │       └── a
          └── b
              └── a
    
por Zettt 14.06.2014 / 15:08

6 respostas

6
find . -depth -print0 | perl -0lne '
  if ("$_/" =~ m{/Caches(/.*)}s && $1 !~ m{/Snapshots/}) {rmdir $_ or unlink $_}'

Se o seu find não for compatível com -print0 , você poderá substituí-lo por -exec printf '%sperl' {} + .

A idéia é imprimir a lista de arquivos terminados em NUL (como 0 é o único byte que não pode ocorrer em um caminho de arquivo) e usar a opção -n -0 with $_ para executar alguns código para cada um desses nomes de arquivos (com -depth definido para o nome do arquivo).

Com depth , os arquivos são impressos antes do diretório pai. Nós removemos apenas arquivos ou diretórios (assumindo que eles estão vazios, e é por isso que é importante processar a lista em /Caches/ order) se o caminho contiver /Snapshosts/ não seguido por %code% .

    
por 14.06.2014 / 18:39
7

Estou um pouco confuso com a redação da pergunta. Se o que você deseja fazer é excluir tudo no diretório ./Library/Caches , exceto por uma única pasta chamada Snapshots , não é necessário usar find . Em bash , as shell globs são a maneira mais simples:

shopt -s extglob  # probably already enabled
echo Library/Caches/!(Snapshots)

Se isso imprimir todos os arquivos / diretórios que você deseja excluir, substitua echo por rm -f -- .

Se houver vários diretórios Snapshots em diferentes níveis da árvore de diretórios abaixo de ./Library/Caches que você deseja preservar, então com o GNU find você pode fazer:

find Library/Caches ! -path '*Snapshots*'

Isso deve imprimir todos os arquivos / diretórios, excluindo aqueles que possuem Snapshots em seu caminho. Ele incluirá diretórios que contêm (ou cujos filhos contêm) Snapshots diretórios, mas find ... -delete não os excluirá e, em vez disso, imprimirá um erro dizendo que eles não estão vazios. Quando estiver satisfeito, adicione -delete ao final.

Uma ressalva é que isso deixará quaisquer arquivos com o nome Snapshots intact. Se isso for um problema, faça:

find Library/Caches \( ! -path '*Snapshots*' -o -type f -name Snapshots \)

Adicione novamente -delete quando estiver feliz.

    
por 14.06.2014 / 17:38
2

Eu não sou um% fe_de% feiticeiro, então eu não quero dizer que você não pode fazer isso com find , mas eu sei que isso pode ser feito com algumas linhas de find . Dado que eu entendo sua estrutura de diretórios corretamente:

#!/bin/bash

for i in Library/Caches/*; do
    if [[ -d "$i" ]]; then
         [[ "$i" =~ "Snapshots" ]] ||  echo "rm-ing  $i" # change to rm -rf "$i" to use
    fi
done

A instrução bash retorna cada item em for . A instrução Library/Caches/ verifica se cada item é um diretório e, se estiver, então seu nome é verificado para ver se ele contém "Instantâneos", if [[ -d "$i" ]] . Como não há um operador para negar uma correspondência de expressão regular, como [[ "$i" =~ "Snapshots" ]] , usei !=~ para executar || se o comando anterior não for bem-sucedido, por exemplo o nome do diretório não contém instantâneos.

Isso será executado em qualquer sistema moderno usando rm , mas deve ter bash . Além disso, talvez seja necessário brincar com a estrutura de diretórios, mas isso deve ser feito para você.

    
por 14.06.2014 / 16:04
0
cd ./Library/Caches
mv ./Snapshots ../    
sh -c 'rm -rf -- .[!.]* *' 
mv ../Snapshots ./

Você não precisa definir nenhuma opção de shell persistente. Apenas mova o diretório, exclua tudo e mova-o de volta. Uso o .[!.] glob acima para manipular .files e colocá-lo em uma declaração sh porque bash ou zsh provavelmente não interpretarão o globo do escudo portátil corretamente. Mas se não houver .files , você pode usar:

rm -rf -- *

.. em vez disso. Só não faça isso em nenhum diretório em que você não quer tudo excluído.

Você pode aplicar essa mesma lógica recursivamente - se houver várias instâncias de ./Caches/Snapshots , por exemplo. Primeiro, faça um diretório hold no mesmo sistema de arquivos que ./Library/ :

mkdir -p hold ; hold=${PWD}/hold/Snapshots

Agora, find all Snapshots dirs, salve-os em outro lugar e exclua o restante:

cd ./Library
find . -type d -name Snapshots -exec sh -c '
    [ "$0" != "${0%/Caches/Snapshots}" ] && {
    mv "$0" '"${hold}"' &&
    ( cd "${0%/*}" && rm -rf -- .[!.]* * ) && 
    mv '"${hold}"' "$0"
}' \{\} \;
    
por 14.06.2014 / 18:18
0

Primeira parte: encontre diretórios chamados caches e faça algo com eles

find . -name Caches -type d -exec … \;

Segunda parte: percorra um diretório de cache e remova tudo, mas mantenha Snapshots de subdiretórios e seu conteúdo (assim como os caminhos que levam a eles). Faça uma travessia em profundidade, para que os diretórios possam ser excluídos assim que ficarem vazios.

    find /path/to/Caches -depth -name Snapshots -type d -prune \
                             -o \( -type d -empty -o ! -type d \) -delete

Agora combine-os juntos.

find . -name Caches -type d -exec
    find {} -depth -name Snapshots -type d -prune \
                -o \( -type d -empty -o ! -type d \) -delete
    
por 15.06.2014 / 21:20
-1

Por que não encontrar o que você precisa excluindo o que você deseja manter?

Procure arquivos em vez de diretórios:

find . -type f | grep Cashes | grep -v Snapshot | xargs rm

Assim, você encontrará todos os arquivos dos diretórios atuais e, em seguida, selecionará apenas os arquivos que estão nos diretórios Cashes , excluindo os arquivos que estão no diretório Snapshot e, em seguida, removendo o restante.

Acima pode deixar diretórios vazios, mas você pode jogar com find opções para obter o resultado necessário.

    
por 14.06.2014 / 16:48

Tags