Remova todos os arquivos, exceto alguns de um diretório

215

Ao usar sudo rm -r, como posso apagar todos os arquivos, com exceção do seguinte:

textfile.txt
backup.tar.gz
script.php
database.sql
info.txt
masjoko
fonte
5
Soa como uma pergunta para unix.stackexchange.com
Jason
1
Existem duas maneiras de ler esta pergunta, e as respostas existentes abrangem ambas as interpretações: A: preservar arquivos com os nomes especificados diretamente localizados no diretório de destino e - como rm -rimplica - excluir tudo o mais, incluindo subdiretórios - mesmo que contenham arquivos com os nomes especificados; OU: (b) percorra toda a subárvore do diretório de destino e, em cada diretório, exclua todos os arquivos, exceto aqueles com os nomes listados.
precisa saber é o seguinte

Respostas:

219
find [path] -type f -not -name 'textfile.txt' -not -name 'backup.tar.gz' -delete

Se você não especificar -type fachado também diretórios lista, que você pode não querer.


Ou uma solução mais geral, utilizando a combinação muito útil find | xargs:

find [path] -type f -not -name 'EXPR' -print0 | xargs -0 rm --

por exemplo, exclua todos os arquivos não txt no diretório atual:

find . -type f -not -name '*txt' -print0 | xargs -0 rm --

A combinação print0e -0é necessária se houver espaços em qualquer um dos nomes de arquivos que devem ser excluídos.

awi
fonte
2
parece xargs tem um tamanho limite de texto
frazras
26
excluir vários padrões:find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
Siwei Shen, 18/03/2013
5
e os diretórios? ele excluirá todos os arquivos, mas remove pastas ?!
orezvani
31
Em vez de "| xargs rm", find aceita um parâmetro -delete.
Emil Stenström
1
em vez de -print0 | xargs -0 rm --você pode apenas-delete
Andy
150
rm !(textfile.txt|backup.tar.gz|script.php|database.sql|info.txt)

O extglob (correspondência estendida de padrões) precisa estar ativado no BASH (se não estiver ativado):

shopt -s extglob
pl1nk
fonte
2
Eu recebo "erro de sintaxe próximo inesperado símbolo` ( "quando eu faço shopt -s extglob; rm -rf !(README|LICENSE)Qualquer ideia porquê.?
Dennis
@ nic Não me lembro, desculpe. Eu provavelmente acabei usando findcom a -deleteopção
Dennis
Esta é a melhor solução para mim e ele funciona por padrão no meu Ubuntu 12.04.4 LTS sem necessidade de shopt
xtian
3
@nic, @Dennis: O erro de sintaxe sugere que algo diferente de bashfoi usado, por exemplo dash, onde extglobnão é suportado. No entanto, em um shell interativo bash , o comando TAMBÉM não funcionará como indicado, embora por razões diferentes. O resumo: execute shopt -s extglobBY ITSELF; Uma vez habilitado com êxito (verifique com shopt extglob), execute rm -rf !(README|LICENSE). (Embora extglobainda não está habilitado, !(...)é avaliada pela expansão história antes dos comandos são executados, uma vez que isso provavelmente falhar, NEM comando é executado, e extglob. Nunca é ligado)
mklement0
2
@nic, @Dennis, @ mklement0: Eu tive o mesmo problema com "erro de sintaxe próximo ao token inesperado (" ao executar o comando em um arquivo .sh (#! / bin / bash), mas não quando eu o estava executando em um comando . interface de linha Acontece que, além do shopt -s extglobprazo na interface de linha de comando, eu tinha de executá-lo novamente dentro de meu arquivo de script Isso resolveu o problema para mim..
Ahresse
41

find . | grep -v "excluded files criteria" | xargs rm

Isso listará todos os arquivos no diretório atual e, em seguida, todos aqueles que não correspondem aos seus critérios (cuidado com os nomes dos diretórios correspondentes) e depois os remove.

Atualização : com base na sua edição, se você realmente deseja excluir tudo do diretório atual, exceto os arquivos listados, isso pode ser usado:

mkdir /tmp_backup && mv textfile.txt backup.tar.gz script.php database.sql info.txt /tmp_backup/ && rm -r && mv /tmp_backup/* . && rmdir /tmp_backup

Ele criará um diretório de backup /tmp_backup(você tem privilégios de root, certo?), Moverá os arquivos listados para esse diretório, excluirá recursivamente tudo do diretório atual (você sabe que está no diretório certo, não é?), Moverá de volta ao diretório atual /tmp_backupe, finalmente, exclua /tmp_backup.

Eu escolho o diretório de backup como raiz, porque se você estiver tentando excluir tudo recursivamente da raiz, seu sistema terá grandes problemas.

Certamente, existem maneiras mais elegantes de fazer isso, mas essa é bem direta.

darioo
fonte
2
Trabalha também muito bem com egrep, por exemplo, para a limpeza de arquivos de látex intermediários:find . | egrep -v "\.tex|\.bib" | xargs rm
mtsz
comando incrível! para a remoção de diretórios apenas mudar para rm -r
Aris
1
Se você deseja simplesmente excluir tudo no diretório atual, exceto os critérios excluídos: find . -maxdepth 1 | grep -v "exclude these" | xargs rm -rfunciona muito mais rápido, pois não precisa detalhar os diretórios desnecessariamente.
precisa saber é
Re- findpipeline: deixando de lado os problemas de eficiência (três comandos são usados ​​para o que findpoderia ser feito sozinho), isso não funcionará como planejado com nomes de arquivos com espaços incorporados e potencialmente excluirá os arquivos errados.
usar o seguinte código
Um comando que armazena arquivos "a serem salvos" em outro local ( /tmp_backup) não termina bem se for interrompido - da perspectiva do usuário, todos os arquivos desapareceram, a menos que eles saibam para onde procurá-los para recuperá-los. . Por esse motivo, não sou a favor desse tipo de estratégia.
Craig McQueen
20

Supondo que os arquivos com esses nomes existam em vários locais na árvore de diretórios e você queira preservar todos eles:

find . -type f ! -regex ".*/\(textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt\)" -delete
Pausado até novo aviso.
fonte
19

Você pode usar a variável de ambiente GLOBIGNORE no Bash.

Suponha que você queira excluir todos os arquivos, exceto php e sql, e faça o seguinte -

export GLOBIGNORE=*.php:*.sql
rm *
export GLOBIGNORE=

Definir GLOBIGNORE como este ignora php e sql de curingas usados ​​como "ls *" ou "rm *". Portanto, usar "rm *" após definir a variável excluirá apenas os arquivos txt e tar.gz.

theharshest
fonte
6
+1; Uma alternativa mais simples de definir e restaurar a GLOBIGNOREvariável é usar um subshell:(GLOBIGNORE='*.php:*.sql'; rm *)
mklement0
19

Eu prefiro usar a lista de subconsultas:

rm -r `ls | grep -v "textfile.txt\|backup.tar.gz\|script.php\|database.sql\|info.txt"`

-v, --invert-match seleciona linhas não correspondentes

\| Separador

Nick Tsai
fonte
1
Solução elegante
Joshua Salazar
9

Desde que ninguém mencionou:

  • copie os arquivos que você não deseja excluir em um local seguro
  • excluir todos os arquivos
  • mover os arquivos copiados de volta no lugar
gniourf_gniourf
fonte
2
É mais complicado porque você precisa cuidar das permissões depois de copiá-las.
Romulus
2
@RemusAvram Você pode usar opções apropriadas com cpou rsyncpara preservar permissões. De qualquer forma, esse é apenas um método alternativo (dado como sugestão) que tem seu lugar aqui, como resposta ao OP.
Gnourf_gniourf
Isso pode não ser apropriado em muitas situações em que os arquivos a serem retidos estão sendo usados ​​ativamente por outros processos. Também é complicado que os arquivos a serem removidos sejam apenas um pequeno subconjunto e um grande número de arquivos esteja envolvido.
codeforester
@ codeforester: com certeza. Mas há situações em que isso é apropriado ... na verdade, eu realmente não entendo o objetivo do seu comentário :).
precisa saber é o seguinte
6

Você pode escrever um loop for para isso ...%)

for x in *
do
        if [ "$x" != "exclude_criteria" ]
        then
                rm -f $x;
        fi
done;
mishunika
fonte
6

Um pouco atrasado para o OP, mas espero que útil para quem chega aqui muito mais tarde pelo google ...

Encontrei a resposta em @awi e comente sobre -delete em @Jamie Bullock realmente útil. Um utilitário simples para que você possa fazer isso em diretórios diferentes, ignorando nomes / tipos de arquivos diferentes a cada vez com digitação mínima:

rm_except (ou o que você quiser nomear)

#!/bin/bash

ignore=""

for fignore in "$@"; do
  ignore=${ignore}"-not -name ${fignore} "
done

find . -type f $ignore -delete

por exemplo, para excluir tudo, exceto arquivos de texto e foo.bar:

rm_except *.txt foo.bar 

Semelhante a @mishunika, mas sem a cláusula if.

lhuber
fonte
5

Se você estiver usando o zshque eu recomendo.

rm -rf ^file/folder pattern to avoid

Com extended_glob

setopt extended_glob
rm -- ^*.txt
rm -- ^*.(sql|txt)
sudo bangbang
fonte
4

Tentando trabalhar com:

rm -r !(Applications|"Virtualbox VMs"|Downloads|Documents|Desktop|Public)

mas nomes com espaços são (como sempre) difíceis. Tentei também com Virtualbox\ VMsas cotações. Exclui sempre esse diretório ( Virtualbox VMs).

juanfal
fonte
NÃO funciona para arquivos. rm !(myfile.txt)remove tudo, inclusive #myfile.txt
khaverim
deve executar shopt -s extglobprimeiro como @ pl1nk apontou
zhuguowei
Sim, é muito importante para ativar estendido englobamento ( extglob ) em bash, eu estou fazendo isso em uma base de rotina diária, ao longo de alguns Macs em laboratórios: shopt -s extglobe, em seguida, cd /Users/alumno/e, finalmente, rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library) Leia sobre englobamento estendido aqui
juanfal
4

Somente:

rm $(ls -I "*.txt" ) #Deletes file type except *.txt

Ou:

rm $(ls -I "*.txt" -I "*.pdf" ) #Deletes file types except *.txt & *.pdf
wyx
fonte
Isto não é recomendado. Analisar lssaída pode se tornar um problema. Veja aqui para informações detalhadas.
RJ
2

Torne os arquivos imutáveis. Nem mesmo o root poderá excluí-los.

chattr +i textfile.txt backup.tar.gz script.php database.sql info.txt
rm *

Todos os outros arquivos foram excluídos.
Eventualmente, você pode redefini-los mutáveis.

chattr -i *
L'alligator des abers
fonte
0

Isso é semelhante ao comentário de @ siwei-shen, mas você precisa da -obandeira para fazer vários padrões. A -obandeira significa 'ou'

find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm

Daniel Chen
fonte
0

Você pode fazer isso com duas seqüências de comandos. Primeiro defina uma matriz com o nome dos arquivos que você não deseja excluir:

files=( backup.tar.gz script.php database.sql info.txt )

Depois disso, percorra todos os arquivos no diretório que você deseja excluir, verificando se o nome do arquivo está na matriz que você não deseja excluir; caso contrário, exclua o arquivo.

for file in *; do
  if [[ ! " ${files[@]} " ~= "$file"  ]];then
    rm "$file"
  fi
done
Leonardo Hermoso
fonte
A comparação do regex está incorreta - preservará qualquer arquivo cujo nome seja uma subcadeia de um dos arquivos protegidos (embora os espaços ao redor atenuem um pouco isso; mas os nomes de arquivos podem conter espaços). Você deve coletar uma matriz de todos os arquivos, subtrair os arquivos que deseja excluir dessa matriz e remover os arquivos restantes.
Tripleee
-1

Como ninguém ainda mencionou isso, em um caso específico:

OLD_FILES=`echo *`
... create new files ...
rm -r $OLD_FILES

(ou apenas rm $OLD_FILES)

ou

OLD_FILES=`ls *`
... create new files ...
rm -r $OLD_FILES

Você pode precisar usar shopt -s nullglobse alguns arquivos estiverem lá ou não:

SET_OLD_NULLGLOB=`shopt -p nullglob`
shopt -s nullglob
FILES=`echo *.sh *.bash`
$SET_OLD_NULLGLOB

sem nullglob, echo *.sh *.bashvocê pode obter "a.sh b.sh * .bash".

(Dito tudo isso, eu mesmo prefiro essa resposta , mesmo que ela não funcione no OSX)

18446744073709551615
fonte
A resposta existente de Leonardo Hermoso faz isso com menos erros. Isso falhará para nomes de arquivos com espaços; o uso de uma matriz resolve elegantemente esse problema específico (e também evita de forma menos crucial o uso de maiúsculas para suas variáveis ​​privadas, o que geralmente deve ser evitado).
Tripleee
-3

Em vez de usar um comando direto, mova os arquivos necessários para temp dir para fora do dir atual. Em seguida, exclua todos os arquivos usando rm *ou rm -r *.

Em seguida, mova os arquivos necessários para o diretório atual.

Ajeesh
fonte
Isso pode não ser apropriado em muitas situações em que os arquivos a serem retidos estão sendo usados ​​ativamente por outros processos. Também é complicado que os arquivos a serem removidos sejam apenas um pequeno subconjunto e um grande número de arquivos esteja envolvido.
Codeforester
-3

Remova tudo, exclua file.name:

ls -d /path/to/your/files/* |grep -v file.name|xargs rm -rf
mik-mak
fonte
2
Isso falhará horrivelmente e poderá causar perda de dados se o seu diretório / arquivos tiver espaços ou caracteres incomuns. Você nunca deve analisar sl. mywiki.wooledge.org/ParsingLs
RJ