Excluir um padrão da correspondência global

54

Eu tenho vários arquivos com o mesmo nome de arquivo base. Eu gostaria de remover todos, exceto um

foo.org #keep
foo.tex #delete
foo.fls #delete
foo.bib #delete
etc

Se eu não precisasse ficar com um, sei que poderia usá-lo rm foo.*.

O TLDP demonstra ^para negar uma correspondência. Por tentativa e erro, consegui descobrir que

rm foo.*[^org]

faz o que eu preciso, mas eu realmente não entendo a sintaxe.

Além disso, embora não seja uma limitação no meu caso de uso, acho que esse padrão também ignora foo.oe foo.or. Como é que este trabalho padrão, e o que seria um glob que ignora única foo.org parece?

Jake
fonte
11
Como complemento à resposta do @glen, vale mencionar que rm foo.*[^org]remove todos os arquivos cujo último caractere não é nem o, rou g, portanto, também foo.foonão corresponderia.
jimmij
Você está usando um Regular Expression. Você deve ter cuidado com seus personagens de agrupamento. Usando suportes que você especificou um significado classe de personagem que você exclua todos os arquivos que tinham uma extensão com as letras o, rou gem qualquer ordem. Use parênteses para criar um grupo e preservar a ordem dos caracteres.
Sr. Mascaro
3
@ jbarker2160 - isso não é realmente uma expressão regular, é mais comumente chamado de glob (ou padrão de nome de arquivo ), que é mais ou menos um subconjunto de uma expressão regular - consulte a seção de correspondência de padrões da página de manual do bash para obter detalhes. Seu padrão foo.*[^org]corresponderá a qualquer nome de arquivo que comece com foo.um ou mais caracteres após o ponto em que o último caractere não é o, r ou g. Então, seria igual foo.orb, mas não foo.orgou foo.orou foo.o. A resposta de GlennJackman mostra como habilitar os recursos estendidos de correspondência de padrões para negar uma correspondência.
Johnny

Respostas:

52
shopt -s extglob
echo rm foo.!(org)

Isso é "foo". seguido por qualquer coisa que não seja "org"

ref: https://www.gnu.org/software/bash/manual/bashref.html#Pattern-Matching

Glenn Jackman
fonte
Eu tentei fazer o mesmo, mas com suportes e, aparentemente, ao usar colchetes ele não funciona
Donato
4
Qual é a sintaxe para corresponder a vários nomes de arquivo? digamos que quero excluir .org, .png, .txt?
Freedo 17/01/19
@Freedo @()para uma lista de padrões: stackoverflow.com/a/217208/3779853
phil294
23

No bash, você também pode usar GLOBIGNORE="*.org"; rm -i foo*.

E unset GLOBIGNOREquando terminar.

Não é realmente melhor do que shopt -s extglob, mas acho mais fácil lembrar.

mivk
fonte
5
@Ruslan Isso não funciona. Você deve fazer( GLOBIGNORE="*.org"; rm -i foo* )
DBedrenko
3
Observe se você deseja expandir a lista de GLOBIGNORE="*foo*:*bar*"
itens
7

Um cano pode fazer?

ls * | grep -v "foo.org" | xargs -I {} echo {}

(obviamente, você pode substituir echo por rm na última cadeia).

Adobe
fonte
Útil se necessário em apenas uma linha.
bruceskyaus
11
Mais fácil de lembrar (para mim, eu faço esse tipo de coisa com frequência) e permite que um processamento mais complexo seja inicializado :)
drevicko 04/07
11
ls -1deve ser mais confiável para garantir que todos os arquivos sejam tratados grepseparadamente
MichaelChirico
0

O OP estava muito próximo:

rm foo.*[^o][^r][^g]

embora neste caso o *seja desnecessário.

MrMas
fonte