Removendo arquivos com uma certa extensão, exceto um arquivo do terminal

36

Eu preciso remover todos os arquivos com a extensão .gif, exceto um arquivo com o nome say "filename.gif". Qual é a melhor maneira de fazer isso no terminal?

O comando rm *.gif remove todos os arquivos gif incluindo o arquivo filename.gif .

    
por Seth 15.02.2013 / 19:02

4 respostas

66

Esta é a solução simples que você provavelmente deve usar:

mv filename.gif filename.gif.keep
rm *.gif
mv filename.gif.keep filename.gif

Não há nada de especial na extensão .keep , isso faz com que o nome do arquivo não termine em .gif .

Se você não deve renomear o arquivo (e existem scripts situações em que isso é importante):

for X in *.gif; do
    if [ "$X" != "filename.gif" ]; then
        rm "$X"
    fi
done

Ou você pode escrevê-lo mais curto assim:

for X in *.gif; do [ "$X" != "filename.gif" ] && rm "$X"; done

Você pode preferir usar find ; é muito poderoso, você pode considerá-lo mais legível, e lida melhor com nomes estranhos de arquivos com caracteres como * neles .

find . -maxdepth 1 -not -name 'filename.gif' -name '*.gif' -delete

Eu usei o operador -not para facilitar a leitura, mas se a conformidade com POSIX for importante - se você ' não está usando o GNU find, ou se é para um script que você pretende redistribuir para outros ou rodar em uma variedade de sistemas - você deve usar o operador ! :

find . -maxdepth 1 ! -name 'filename.gif' -name '*.gif' -delete

Uma coisa útil sobre find é que você pode modificar facilmente o comando para distinção entre maiúsculas e minúsculas, para que ele encontre e exclua arquivos com extensões como .GIF também:

find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete

Por favor, note que usei -iname no lugar de -name para o padrão de pesquisa *.gif , mas eu não usei para filename.gif . Presumivelmente, você sabe exatamente para o que seu arquivo é chamado, e -iname corresponderá a letras maiúsculas alternativas não apenas na extensão , mas em qualquer lugar no nome do arquivo.

Todas essas soluções excluem apenas arquivos que residem imediatamente no diretório atual . Eles não excluem arquivos não contidos no diretório atual e não excluem arquivos que residem em subdiretórios do diretório atual.

Se você deseja excluir arquivos em todos os lugares contidos no diretório atual (ou seja, inclusive em subdiretórios e em subdiretórios desses subdiretórios e assim por diante - arquivos contidos no diretório atual ou em qualquer um de seus descendentes), use find sem maxdepth -1 :

find . -not -name 'filename.gif' -name '*.gif' -delete

Cuidado com isso!

Você também pode definir outros valores com -maxdepth . Por exemplo, para excluir arquivos no diretório atual e seus filhos e netos, mas não mais profundamente:

find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete

Apenas certifique-se de nunca colocar -delete antes das outras expressões! Você verá que eu sempre coloquei -delete no final. Se você colocá-lo no começo, ele seria avaliado primeiro, e todos os arquivos em . (incluindo arquivos que não terminam em .gif e arquivos em sub-sub-sub ... diretórios de . ) seriam excluídos!

Para mais informações , consulte as páginas de manual de bash e sh e para os comandos usados em estes exemplos: mv , rm , [ e (especialmente) find .

    
por Eliah Kagan 15.02.2013 / 19:33
27

Se você estiver usando bash (o shell padrão), a opção extglob shell permite que você use uma sintaxe estendida de correspondência de padrões. Para ativá-lo, use o comando shopt builtin:

shopt -s extglob

(incluo essa linha no meu arquivo .bashrc .)

Entre outras coisas, ele concede acesso ao operador !() , que corresponde a qualquer padrão que não esteja dentro dos parens. Para o seu propósito:

rm !(filename).gif

Mais informações estão disponíveis em man bash em "Correspondência de padrões".

    
por eswald 16.02.2013 / 00:34
13

Abra um Terminal com Ctrl + Alt + T e digite:

find . -type f -name "*.gif" -and -not -name "filename.gif" -exec rm -vf {} \;

A diferença entre -delete e -exec rm -vf {} \; é que, com a segunda opção, você poderá ver quais arquivos foram removidos, devido ao sinal -v . Isso é algo que não pode ser feito com a opção -delete . ( -name -delete imprime os nomes dos arquivos, mas rm com -v revela se cada arquivo foi com sucesso excluído.)

    
por efthialex 15.02.2013 / 19:15
1

Existe a variável GLOBIGNORE . De man bash :

GLOBIGNORE
      A colon-separated list of patterns defining the set of filenames
      to be ignored by pathname expansion.  If a filename matched by a
      pathname expansion pattern also matches one of the  patterns  in
      GLOBIGNORE, it is removed from the list of matches.

Portanto, uma maneira simples é apenas definir GLOBGINORE para o nome do arquivo em questão:

$ touch {a,b,c,d}.png
$ echo *.png
a.png b.png c.png d.png
$ GLOBIGNORE=c.png
$ echo *.png
a.png b.png d.png

Então, no seu caso:

GLOBIGNORE=filename.gif; rm *.gif

É claro que, como GLOBIGNORE contém padrões, você pode usá-lo sempre que quiser excluir um padrão:

$ GLOBIGNORE='[a-c].png'; echo *.png
d.png
$ touch bd.png; GLOBIGNORE='?.png'; echo *.png
bd.png

Uma vantagem (?!) de GLOBIGNORE é que a definição exclui automaticamente . e .. de ser correspondido e habilita dotglob :

The  GLOBIGNORE shell variable may be used to restrict the set of file‐
names matching a pattern.  If GLOBIGNORE is set, each matching filename
that also matches one of the patterns in GLOBIGNORE is removed from the
list of matches.  The filenames ''.''  and ''..''  are  always  ignored
when  GLOBIGNORE is set and not null.  However, setting GLOBIGNORE to a
non-null value has the effect of enabling the dotglob shell option,  so
all other filenames beginning with a ''.''  will match.  To get the old
behavior of ignoring filenames beginning with a ''.'', make ''.*''  one
of  the  patterns  in  GLOBIGNORE.  The dotglob option is disabled when
GLOBIGNORE is unset.

Assim, uma maneira simples de excluir todos arquivos e pastas em um diretório:

GLOBIGNORE=.; rm -r *

O * corresponderá aos nomes dos arquivos que começam com . , pois GLOBIGNORE ativou dotglob , mas não corresponderá a . ou .. , portanto você não afetará o diretório pai dessa maneira .

    
por muru 12.03.2016 / 19:45