Como excluir todos os arquivos em um diretório, exceto alguns?

123

Preciso excluir todos os arquivos em um diretório, mas excluir alguns deles. Por exemplo, em um diretório com os arquivos a b c ... z, preciso excluir todos, exceto ue p. Existe uma maneira fácil de fazer isso?

Um tiro
fonte
As respostas abaixo são muito melhores, mas você pode criar os arquivos para salvar somente leitura, excluir tudo e alterá-los para as permissões originais (desde que você não use rm -f). Você precisaria saber quais permissões restaurar e saber que nada precisava de acesso de gravação a elas durante o processo. É por isso que as outras respostas são melhores.
21413 Joe
1
Se você também deseja excluir arquivos ocultos, execute shopt -s dotglobantes de executar rm (...).

Respostas:

108

O que faço nesses casos é digitar

rm *

Em seguida, pressiono Ctrl+ X, *para expandir * para todos os nomes de arquivos visíveis.

Depois, basta remover os dois arquivos que gosto de manter da lista e finalmente executar a linha de comando.

Der Hochstapler
fonte
25
Eu acho que isso funciona apenas enquanto a lista de arquivos que *também se expande não está ficando muito longa. : -}
Frerich Raabe
9
Esc seguido por * também expandirá o "*".
slowpoison
2
@SantoshKumar: Isso não faz sentido para mim. A expansão sempre funcionará, não depende de qual comando você deseja usar posteriormente.
Der Hochstapler
2
@OliverSalzburg Desculpe, a combinação é um pouco confusa. Eu acho que você deveria escrever como Ctrl+ Shift+ x+*
Santosh Kumar
2
@SantoshKumar: Mas essa não é a combinação.
Der Hochstapler
143

Para rmtodos, exceto u,pno bash, basta digitar:

rm !(u|p)

Isso requer que a seguinte opção seja configurada:

shopt -s extglob

Ver mais: glob - Wiki de Greg

sparkie
fonte
1
você deve ter 'extglobbing' ativo: shopt -s extglob
sparkie
18
Você precisa shopt -s extglob, @Ashot. Além disso, são apenas arquivos, não diretórios, e é por isso que removi as -rfopções do seu comando.
slhck
4
Se você precisar excluir um arquivo de uma seleção de arquivos, tente o seguinte: rm !(index).html. Isso excluirá todos os arquivos que terminam em ".html", com a exceção de "index.html".
Mzuther
71

Você pode usar find

find . ! -name u ! -name p -maxdepth 1 -type f -delete
  • ! nega a próxima expressão
  • -name especifica um nome de arquivo
  • -maxdepth 1fará do processo find apenas o diretório especificado ( findpor padrão, percorre os diretórios)
  • -type f processará apenas arquivos (e não por exemplo diretórios)
  • -delete excluirá os arquivos

Você pode ajustar as condições na página de manual do find

Atualizar

  • Lembre-se de que a ordem dos elementos das expressões é significativa (consulte a documentação)
  • Teste seu comando primeiro usando em -printvez de-delete

    find . ! -name u ! -name p -maxdepth 1 -type f -print
Matteo
fonte
5
A ordem dos predicados é crítica aqui. Se um posto -deletelogo após .será desastre (irá apagar todos os arquivos em CWD)
Michał Šrajer
Isso pode ser escrito de forma mais compacta comofind . -maxdepth 1 -type f -name '[^up]' -delete
kojiro
4
@kojiro sim, mas apenas para arquivos com apenas uma letra. Com nomes mais complexos, o regex pode ser uma bagunça.
Matteo
2
findé meu melhor amigo, especialmente quando há muitos arquivos para glob
Terence Johnson
43

Simples:

mvos arquivos que você deseja em um diretório superior, rmo diretório e depois mvos retorna.

user176581
fonte
13
Offcourse, mova-os para um diretório mais alto. Tente não mv-los para um subdiretório que você está excluindo ...
Konerak
@ Konerak: rmsem -r, não removerá subdiretórios.
Reinierpost
11
Isto irá sobrescrever arquivos com o mesmo nome no diretório de destino
Matteo
7
Estou com o voto negativo porque, embora possa ser útil, ele também não é atômico e remove efetivamente todos os arquivos do diretório durante um curto período de tempo; isso não seria aceitável se, por exemplo, os arquivos estivessem sendo compartilhados na rede.
Sam Hocevar
15

Um pouco semelhante a esta resposta, mas nenhuma opção especial é necessária, até onde eu sei o seguinte é uma funcionalidade "antiga" suportada por qualquer shell (vagamente) / bin / sh (por exemplo, bash, zsh, ksh, etc)

rm [^up]
hlovdal
fonte
2
Isso funciona para os nomes de arquivos de 1 caractere. Para nomes mais longos, a resposta do sparkie é melhor.
glenn jackman
3
O que haveria de errado rm [^up]*? Faço coisas semelhantes com bastante frequência.
um CVn em
3
@ MichaelKjörling - isso excluiria todos os arquivos iniciados com u ou p, não apenas aqueles com os nomes u e p. Eu acho que o OP (@Ashot) significava az e u, p, etc. simbolicamente e não literalmente.
Sudipta Chatterjee
4
@HobbesofCalvin Isso excluiria todos os arquivos que não começam com u ou p, e não aqueles que começam com eles.
Rjmunro
@rjmunro - obrigado, perdi essa! :)
Sudipta Chatterjee
11

Fazendo isso sem encontrar:

ls | grep -v '(u|p)' | xargs rm

(Edite: "u" e "v", como em outros lugares aqui, estão sendo usados ​​como versões genéricas de regexes inteiras. Obviamente, você deve ter cuidado para ancorar suas regexes para evitar a correspondência de muitas coisas.)

Você definitivamente vai querer um script se estiver fazendo muito disso, como outros sugeriram.

tid
fonte
O grep não manipula regexpt estendido por padrão: use -Eoregrep
Matteo
2
isso excluirá qualquer arquivo que contenha um uou ump
Matteo
@ Matteo Não, não vai. O grep não está cumprimentando os arquivos, está cumprindo a saída do comando ls. Você está pensando em algo como grep -L (u|p)' * | xargs rmwhere -Lsignifica que os nomes de arquivos da lista não contêm uma correspondência.
Rjmunro
4
Ah, você quer dizer qualquer arquivo cujo nome contenha uou pnão qualquer arquivo que contenha a uou a p. Está correto. Você pode corrigir usandoegrep -v '^(u|p)$'
rjmunro
1
Aqui está remover tudo, exceto essas correspondências! ls | grep -v 'vuze\|progs' | xargs rm -rf
Nick
6

No zsh:

setopt extended_glob  # probably in your .zshrc

então

rm ^(u|p)

ou

rm *~(u|p)

A segunda vai funcionar mesmo se você tiver ^em $histcharspara substituição história, e, claro, você pode colocar um glob arbitrária antes da ~.

poolie
fonte
5

GLOBIGNORE utiliza uma lista separada por dois pontos

GLOBIGNORE=u:p
rm *
W_Whalley
fonte
12
Isso não funciona no meu shell (GNU bash 4.1.5 (1)). Certifique-se de testá-lo primeiro com algo um pouco menos prejudicial do querm ou em um diretório de testes!
um CVn em
3

Na era do disquete, eu tinha um executável DOS chamado "Except", que movia temporariamente as coisas para fora do diretório atual e executava um comando, para que você pudesse dizer:

exceto * .txt del *. *

para excluir tudo, menos seus arquivos de texto.

Isso seria uma coisa bastante trivial para implementar como um script de shell e, se esse é o tipo de coisa que você provavelmente fará mais do que o dobro, parece que seria uma boa idéia.

Bill K
fonte
2
Isso me lembrou a mesma coisa. Mas temporariamente se movendo para fora da pasta pode não ser uma boa idéia na era da multitarefa :)
Sedat Kapanoglu
3
 find . -maxdepth 1 ! -name "u" ! -name "p" -type f -exec rm -rf {} \;

Isso excluirá todos os arquivos, exceto u e p no unix

user1803687
fonte
2

Para aqueles que preferem especificar padrões de exclusão complexos arbitrários (abrangendo todos os nomes de arquivos afetados) em um estilo completo de eMexs de regexp, posix-awk ou posix-extended (consulte a página de manual de localização), eu recomendaria este. Exclui ue pno dir atual neste exemplo. Isso pode ser útil para scripts.

find -regextype posix-awk ! -regex './(u|p)' -print0 | xargs -0 rm -rf
sparkie
fonte
Você precisa especificar um diretório antes da expressão (`find. -Regextype ...).
Matteo
-regextypesó funciona em versões GNU
Matteo
Não - minha versão find (aperto debian) definitivamente não requer um diretório explícito antes de a expressão se o diretório atual deve ser usado
sparkie
@sparke: isso só funciona em implementações GNU
Matteo
@parkpark: não definir o diretório (primeiro parâmetro) para findé uma extensão de findcomando GNU . O mesmo se aplica à -regextypeopção. Além disso, seu comando excluirá os arquivos nos subdiretórios também, enquanto a pergunta original claramente perguntou sobre os arquivos em um diretório.
Mikko Rantalainen
1

Eu sempre uso:

rm [a-o,q-t,v-z]*

Isso permitirá que você defina quão granular você deseja torná-lo. Portanto, se você deseja excluir os arquivos a e z, pode usar:

rm [a-o,z]*
J Baron
fonte
1

Ainda outra versão usando xargs:

ls -1 | grep -v do_not_delete | xargs -I files rm "files"

Observe que xargs -Ié necessário para manipular nomes de arquivos, incluindo espaços corretamente.

sebhofer
fonte
1

Ainda outra:

for FILE in ./*; do if [[ $FILE != ./u* ]] || [[ $FILE != ./p* ]];then rm $FILE; fi; done;

É meio demorado e não sei se você poderia transformá-lo facilmente em uma função que poderia acomodar facilmente um número arbitrário de argumentos, mas funciona bem.

E é pura bondade.

dylnmc
fonte
1

Aqui está outra variante. Você pode digitar:

rm -i *

ou:

rm --interactive *

Então rm, você deverá confirmar a exclusão de cada arquivo.

idzikovsky
fonte
1

Usar:

find . -type f ! -name 'u' ! -name 'p' ! -name '*.ext' -delete
find . -type d ! -name 'u' ! -name 'p' ! -name '*.ext' -delete

para excluir todos os arquivos, incluindo os diretórios, exceto os arquivos u, pe .ext.

Renzo Fabián
fonte
0

Uma maneira simples e difícil de estragar: digamos que você queira excluir tudo, exceto * .pdf:

mkdir tmp
mv *.pdf tmp
rm *
mv tmp/* .
rm -r tmp
Talloaktrees
fonte