Unix - exclui arquivos e pastas excluindo PATTERN

9

Recentemente, deparei-me com a tarefa de excluir todos os arquivos / pastas de um diretório, exceto aqueles que correspondessem a um padrão específico. Então preparei um comando unix de linha única para fazer o trabalho. Deve ser apenas uma linha? Eu suponho que não, mas é definitivamente mais legal assim!

Embora o problema seja bem simples, fiquei um pouco surpreso com a complexidade da minha solução. Aqui está o comando que eu usei; NOTA: esta é uma solução ruim porque não lida com nomes de arquivos contendo caracteres de alimentação de linha (o que não importava na minha situação).

ls | grep -v PATTERN | xargs -n1 -IREPLACE rm -rf REPLACE

Eu não usei o comando "find" porque não quero recorrer a pastas correspondentes a PATTERN. Por exemplo, considere a seguinte estrutura de arquivos:

file_foo.txt
first_dir
  |
  +--> contents
  +--> ...
foo_dir
  |
  +--> anotherfile.txt
  +--> morefiles.log
foo_file.txt
somefile.txt

O uso do padrão "foo" deve remover apenas "first_dir" (e seu conteúdo é claro) e "somefile.txt" ( não "anotherfile.txt" ou "morefiles.log"). / p>

Pergunta, existem maneiras melhores (mais elegantes e corretas) de realizar isso?


EDIT:
Recentemente foi trazido à minha atenção que "encontrar" pode ser uma opção melhor :

find * -maxdepth 0 ! -name PATTERN -print0 | xargs -0n1 rm -rf

Esta solução manipula corretamente os caminhos que contêm caracteres de alimentação de linha.

    
por joxl 27.07.2010 / 05:06

3 respostas

9

Os exemplos a seguir têm echo prefixado para que você possa testar os padrões antes de usá-los. Remova o echo para ativar o rm -rf . Substitua rm -ri para solicitar confirmação.

ksh tem uma extensão de correspondência negativa para a globulação:

# ksh
echo rm -rf !(*foo*)

A mesma sintaxe está disponível em bash se você definir a opção extglob :

# bash
shopt -s extglob
echo rm -rf !(*foo*)

zsh tem sua própria sintaxe para isso:

# zsh
setopt extended_glob
echo rm -rf ^*foo*

Ele também pode usar a sintaxe em estilo ksh :

# zsh: ksh-style glob syntax
setopt ksh_glob no_bare_glob_qual
echo rm -rf !(*foo*)

# zsh: ksh-style glob syntax, adapted for the default bare_glob_qual option
setopt ksh_glob bare_glob_qual
echo rm -rf (!(*foo*))
    
por 12.12.2010 / 22:08
7

Aqui está outra solução find . Não tenho certeza se isso tem alguma vantagem real sobre a sua, mas não precisa de xargs e permite a rara possibilidade de * expandir para muitos nomes.

find . -maxdepth 1 ! -name PATTERN -type f -delete

Também adicionei -type f para que não tente excluir diretórios.

Aviso: -delete é poderoso. Eu dei um dos meus arquivos de teste 0 permissões e o comando acima excluiu sem hesitação.

    
por 27.07.2010 / 06:36
0

Você pode usar esse link de script de recuperação, que é muito mais compreensível e pode gerenciar a interação do usuário confirmação:

delete-file: func[file][
    if/else none? find file "/.svn/" [
        delete file
    ][
        print ["keeping" file]
    ]
]
dir: request-dir
ans: ask rejoin ["Do you confirm " dir "? (Yes): "]
if (ans = "Yes") [
    foreach-file dir :delete-file
]
    
por 12.12.2010 / 18:22