Excluir de * na linha de comando

14

Existem muitas situações em que o uso de um * é virtualmente inevitável - por exemplo, rm -rf * em uma pasta que contém milhares de subpastas e arquivos.

Mas e se você quiser excluir apenas um ou dois arquivos ou pastas do comando rm ? Eu pesquisei e só encontrei soluções bastante complicadas como find . -depth -not \( -name 'one' -o -name 'two' \ -o -name 'three' \) -exec rm {} \; como declarado aqui .

Existe a possibilidade de fazer isso de uma maneira mais fácil - sem esse desvio para find ? Por exemplo. rm -rf --exclude='one' --exclude='two' --exclude='three' * como no rsync ou apenas rm -rf -e 'one','two','three' * ?

Talvez até mesmo uma possibilidade geral de excluir itens de * (para que outros comandos como cp , mv , ... não tenham que implementar os próprios)? Algo como *{'one','two','three'} ou algo assim?

    
por David 06.08.2013 / 10:39

3 respostas

31

Para o Bash, existe uma opção do shell chamada extglob que é desativada por padrão para manter a compatibilidade com a sintaxe padrão do shell . O Extglob complementa a sintaxe de operadores adicionais como !() , ?() , @() e outros.

Para alternar extglob , digite shopt -s extglob . Para mantê-lo ativado para o usuário atual, digite echo 'shopt -s extglob' >> ~/.bashrc .

Para o exemplo rm: com extglob você pode usar

rm -rf !(one|two|three)
    
por choroba 06.08.2013 / 10:43
4

Criei exceto exatamente para isso (ainda não consegui adicionar documentação).

Eu tenho uma pasta como esta:

$ ls
a b c d

Digitar except b d fornecerá a e c

$ except b d
ac

Agora você pode canalizar isso para rm .

except b d | xargs -0 rm

Isso pode ser difícil de lembrar, então porque não apenas criar um script em cima de, exceto, chamado rm-except :

#!/usr/bin/env bash

except "$@" | xargs -0 rm

De modo semelhante, é fácil ls-except :

#!/usr/bin/env bash

except "$@" | xargs -0 ls
    
por Helper Method 06.08.2013 / 11:40
1

Como uma alternativa ao extglob (embora seja uma resposta muito boa e todos devem ter shopt -s extglob globstar em seu .bashrc), você pode usar o variável global $ GLOBIGNORE . Digamos que você queira obter todos os arquivos, exceto 'foo.txt' e 'bar baz.txt':

GLOBIGNORE=foo.txt:'bar baz.txt'

... no entanto, isso ativará a opção dotglob do shell, o que significa que * corresponderá aos arquivos iniciados por um ponto (que normalmente estão ocultos). Então você realmente precisa de dois comandos:

GLOBIGNORE=foo.txt:'bar baz.txt'
shopt -u dotglob

Como essa é uma variável global, ela afetará todas as globs que você usar até que $ GLOBSTAR seja cancelado, seja efetuando logout ou com

GLOBIGNORE=

Também funcionará apenas nas cadeias literais transmitidas à variável. Você pode ver o que quero dizer configurando $ GLOBIGNORE e observando a diferença entre esses comandos:

printf '%s\n' *
printf '%s\n' ./*
    
por evilsoup 06.08.2013 / 18:20