Eu preciso remover todos os arquivos com extensão .gif, exceto um arquivo com o nome "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
.
fonte
Eu preciso remover todos os arquivos com extensão .gif, exceto um arquivo com o nome "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
.
Aqui está 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 .keep
extensão, isso apenas faz com que o nome do arquivo temporariamente não termine .gif
.
Se você não deve renomear o arquivo (e há situações de script em que isso é importante):
for X in *.gif; do
if [ "$X" != "filename.gif" ]; then
rm "$X"
fi
done
Ou você pode escrever 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 de arquivos estranhos com personagens como *
eles .
find . -maxdepth 1 -not -name 'filename.gif' -name '*.gif' -delete
Usei o -not
operador para facilitar a leitura, mas se a conformidade com POSIX for importante - se você não estiver usando o GNU find, ou se for para um script que pretende redistribuir para outras pessoas ou executar em uma variedade de sistemas - você deve use o !
operador:
find . -maxdepth 1 ! -name 'filename.gif' -name '*.gif' -delete
Uma coisa útil find
é que você pode modificar facilmente o comando para diferenciar maiúsculas de minúsculas, para que ele encontre e exclua arquivos com extensões como .GIF
:
find . -maxdepth 1 -not -name 'filename.gif' -iname '*.gif' -delete
Observe que eu usei -iname
no lugar do -name
padrão de pesquisa, *.gif
mas não o usei filename.gif
. Presumivelmente, você sabe exatamente como o seu arquivo é chamado e -iname
corresponderá a maiúsculas e minúsculas alternativas não apenas na extensão , mas em qualquer lugar do nome do arquivo.
Todas essas soluções excluem apenas os 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 os arquivos em todos os lugares contidos no diretório atual (ou seja, incluindo subdiretórios e 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
Tenha 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:
find . -maxdepth 3 -not -name 'filename.gif' -name '*.gif' -delete
Apenas certifique-se de nunca colocar -delete
primeiro, antes das outras expressões! Você verá que eu sempre coloco -delete
no final. Se você colocá-lo no início, ele será avaliado primeiro e todos os arquivos em .
(incluindo arquivos que não terminam em .gif
e arquivos em sub-sub-sub-sub ... subdiretórios profundos ... .
) serão excluídos!
Para mais informações , consulte as páginas do manual para bash
e sh
e para os comandos utilizados nestes exemplos: mv
, rm
, [
, e (especialmente) find
.
find
, o que é altamente versátil.find
é realmente um bom achado.find
lidar com nomes de arquivos estranhos com*
eles melhor do que o loop for? O loop for lida com arquivos com*
precisão, porque você usou aspas duplas.Se você estiver usando
bash
(o shell padrão), aextglob
opção shell permitirá que você use uma sintaxe de correspondência de padrão estendida. Para habilitá-lo, use oshopt
comando embutido:(Incluo essa linha no meu
.bashrc
arquivo.)Entre outras coisas, concede acesso ao
!()
operador, que corresponde a qualquer padrão que não esteja dentro do parens. Para seu propósito:Mais informações estão disponíveis em
man bash
"Correspondência de padrões".fonte
extglob
deve ser ativada, mas nada de ruim acontece se estiver desativado (nesse caso, isso simplesmente não funciona). E parece estar ativado por padrão, mesmo que eu não possuashopt -s extglob
nenhum dos meus arquivos de configuração (ou os globais). Se houver uma explicação simples sobre por que ela funciona para mim imediatamente, você pode adicioná-la a esta resposta; ou posso postar uma nova pergunta.Abra um terminal com Ctrl+ Alt+ Te digite:
A diferença entre
-delete
e-exec rm -vf {} \;
é que, com a segunda opção, você poderá ver quais arquivos foram removidos devido ao-v
sinalizador. Isso é algo que não pode ser feito com a-delete
opção. (-name -delete
Imprimirá os nomes de arquivos, masrm
com-v
revela se cada arquivo foi com êxito excluído.)fonte
Existe a
GLOBIGNORE
variável. Deman bash
:Portanto, uma maneira simples é simplesmente definir
GLOBGINORE
o nome do arquivo em questão:Então, no seu caso:
Obviamente, como
GLOBIGNORE
contém padrões, você pode usá-lo sempre que quiser excluir um padrão:Uma vantagem (?!) Disso
GLOBIGNORE
é que a configuração exclui automaticamente.
e..
não corresponde, e permitedotglob
:Portanto, uma maneira simples de excluir todos os arquivos e pastas em um diretório:
Os
*
nomes de arquivos correspondentes serão iniciados com.
, desdeGLOBIGNORE
ativadodotglob
, mas não serão correspondentes.
ou..
, portanto, você não afetará o diretório pai dessa maneira.fonte