Unix - excluir arquivos e pastas, excluindo PATTERN


10

Recentemente, fui confrontado com a tarefa de excluir todos os arquivos / pastas em um diretório, excluindo aqueles que correspondiam a um padrão específico. Então, criei um comando unix de linha única para fazer o trabalho. Deve ser apenas uma linha? Suponho que não, mas é definitivamente mais legal assim!

Embora o problema seja bastante 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 feed 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 recursar em pastas correspondentes a PATTERN. Por exemplo, considere a seguinte estrutura de arquivo:

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").

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


EDIT:
Recentemente, soube que "encontrar" pode ser uma opção melhor :

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

Esta solução manipula corretamente caminhos contendo caracteres de alimentação de linha.


EDIT: alterado erro "the_dir" para corrigir "first_dir".
— joxl

Respostas:


10

Os exemplos a seguir foram echoprefixados para que você possa testar os padrões antes de realmente usá-los. Remova o echopara ativar o rm -rf. Substitua rm -ripara solicitar confirmação.

O ksh tem uma extensão de correspondência negativa para o globbing:

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

A mesma sintaxe está disponível no bash se você definir a extglobopção:

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

O zsh tem sua própria sintaxe para isso:

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

Também pode usar a sintaxe no 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*))

Simples, elegante, lida com caracteres de avanço de linha, (quase) uma linha (eu adicionei shopt -s extglobao meu arquivo .bashrc, agora é uma linha). Perfeito! Eu prometo um voto positivo assim que minha reputação permitir.
— joxl

7

Aqui está outra findsolução. Não tenho certeza se isso tem alguma vantagem real sobre a sua, mas não precisa xargse permite a rara possibilidade de que * se expanda para muitos nomes.

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

Eu também adicionei -type fpara que ele não tentasse excluir diretórios.

Atenção: -deleteé poderoso. Dei a um dos meus arquivos de teste 0 permissões e o comando acima o excluiu sem hesitar.


6
Teste primeiro. Substitua -deletepor -printpara ver se está encontrando os arquivos que você deseja. Se tudo estiver bom, use o histórico de comandos (por exemplo, pressione o botão para cima) para voltar ao comando anterior para garantir que você esteja trabalhando com os mesmos filtros de localização.
— Doug Harris

Leia com atenção, nota que eu faço desejo de diretórios remover. E find -deletenão removerá diretórios não vazios. Observe também que find -maxdepth 1corresponde a "." (diretório atual) que é realmente ruim. Embora eu goste da sua idéia de eliminar xargs, pode-se usar find -execalternativamente. find * -maxdepth 0 ! -name PATTERN -exec rm -rf '{}' \;
— joxl

0

Você pode usar este exemplo de script rebol http://askcodegeneration.com/keep-subversion/, que é muito mais compreensível e que pode gerenciar a interação do usuário, como seleção e confirmação de pasta:

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
]
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.