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

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

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

Estou perguntando: no iOS, cada aplicativo tem seu próprio diretório de caches. Às vezes, eles não são limpos corretamente, dependendo do aplicativo. Com a solução para esta resposta, seria possível limpar caches no iOS e, portanto, otimizar o espaço em disco, quando a unidade dos dispositivos estiver montada em outro computador, por exemplo, com FUSE (iExplorer).

Isto é o que tenho até agora:

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

Isso retorna algo como:

./Library/Caches

Quando faço isso, ls ./Library/Cachesvejo todo o conteúdo e o Snapshotsdiretório, que quero excluir porque, no final das contas, quero -deletetudo, 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

Responder1

Estou um pouco confuso com a formulação da pergunta. Se o que você deseja fazer é excluir tudo do ./Library/Cachesdiretório, exceto uma única pasta chamada Snapshots, não há necessidade de usar find. Em bash, 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 echopor rm -f --.

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

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

Isso deve imprimir todos os arquivos/diretórios, excluindo aqueles que estão Snapshots em seu caminho. Incluirá diretórios que contêm (ou cujos filhos contêm) Snapshotsdiretórios, porém find ... -deletenão os excluirá e, em vez disso, imprimirá um erro informando que eles não estão vazios. Quando estiver satisfeito, adicione -deleteao final.

Uma ressalva é que isso deixará qualquerarquivosnomeado Snapshotsintacto. Se isso for um problema, faça:

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

Adicione novamente -deletequando estiver satisfeito.

Responder2

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

Se o seu findnão suportar -print0, você pode substituí-lo por -exec printf '%s\0' {} +.

A idéia é imprimir a lista de arquivos terminados em NUL (já que 0 é o único byte que não pode ocorrer em um caminho de arquivo) e usar a opção perl's -nwith -0para executar algum código para cada um desses nomes de arquivo (com $_definido para o nome do arquivo ).

Com -depth, os arquivos são impressos antes do diretório pai. Removemos apenas arquivos ou diretórios (supondo que estejam vazios, por isso é importante processar a lista em depthordem) se o caminho /Caches/não contiver seguido por /Snapshosts/.

Responder3

Eu não sou um findfeiticeiro, então não quero dizer que você não pode fazer isso find, mas sei que isso pode ser feito com algumas linhas de bash. Dado que entendi 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 forinstrução retorna cada item em Library/Caches/. A if [[ -d "$i" ]]instrução verifica se cada item é um diretório e, se for, seu nome é verificado para ver se contém "Snapshots", [[ "$i" =~ "Snapshots" ]]. Como não há um operador para negar uma correspondência de regex, como !=~, eu costumava ||executar rmse o comando anterior não tivesse êxito, por exemplo, o nome do diretório não contém instantâneos.

Isso será executado em qualquer sistema moderno usando bash, mas deve ter bash. Além disso, você pode precisar brincar com a estrutura de diretórios, mas isso deve bastar para você.

Responder4

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

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

Segunda parte: percorrer um diretório de cache e remover tudo, mas manter Snapshotsos subdiretórios e seu conteúdo (bem como os caminhos que levam a eles). Faça uma travessia em profundidade, para que os diretórios possam ser excluídos quando ficarem vazios.

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

Agora combine-os.

find . -name Caches -type d -exec
    find {} -depth -name Snapshots -type d -prune \
                -o \( -type d -empty -o ! -type d \) -delete

informação relacionada