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:
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 interativobash , 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..
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:
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.
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
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.
É 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*doif["$x"!="exclude_criteria"]then
rm -f $x;fidone;
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:
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
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*;doif[[!" ${files[@]} "~="$file"]];then
rm "$file"fidone
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:
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.
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
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
rm -r
implica - 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.Respostas:
Se você não especificar
-type f
achado 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
:por exemplo, exclua todos os arquivos não txt no diretório atual:
A combinação
print0
e-0
é necessária se houver espaços em qualquer um dos nomes de arquivos que devem ser excluídos.fonte
find . -type f -not -name '*ignore1' -not -name '*ignore2' | xargs rm
-print0 | xargs -0 rm --
você pode apenas-delete
O extglob (correspondência estendida de padrões) precisa estar ativado no BASH (se não estiver ativado):
fonte
shopt -s extglob; rm -rf !(README|LICENSE)
Qualquer ideia porquê.?find
com a-delete
opçãobash
foi usado, por exemplodash
, ondeextglob
não é suportado. No entanto, em um shell interativobash
, o comando TAMBÉM não funcionará como indicado, embora por razões diferentes. O resumo: executeshopt -s extglob
BY ITSELF; Uma vez habilitado com êxito (verifique comshopt extglob
), executerm -rf !(README|LICENSE)
. (Emboraextglob
ainda 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, eextglob
. Nunca é ligado)shopt -s extglob
prazo na interface de linha de comando, eu tinha de executá-lo novamente dentro de meu arquivo de script Isso resolveu o problema para mim..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:
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_backup
e, 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.
fonte
find . | egrep -v "\.tex|\.bib" | xargs rm
find . -maxdepth 1 | grep -v "exclude these" | xargs rm -r
funciona muito mais rápido, pois não precisa detalhar os diretórios desnecessariamente.find
pipeline: deixando de lado os problemas de eficiência (três comandos são usados para o quefind
poderia ser feito sozinho), isso não funcionará como planejado com nomes de arquivos com espaços incorporados e potencialmente excluirá os arquivos errados./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.Supondo que os arquivos com esses nomes existam em vários locais na árvore de diretórios e você queira preservar todos eles:
fonte
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 -
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.
fonte
GLOBIGNORE
variável é usar um subshell:(GLOBIGNORE='*.php:*.sql'; rm *)
Eu prefiro usar a lista de subconsultas:
fonte
Desde que ninguém mencionou:
fonte
cp
oursync
para 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.:)
.Você pode escrever um loop for para isso ...%)
fonte
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)
por exemplo, para excluir tudo, exceto arquivos de texto e foo.bar:
Semelhante a @mishunika, mas sem a cláusula if.
fonte
Se você estiver usando o
zsh
que eu recomendo.Com
extended_glob
fonte
Tentando trabalhar com:
mas nomes com espaços são (como sempre) difíceis. Tentei também com
Virtualbox\ VMs
as cotações. Exclui sempre esse diretório (Virtualbox VMs
).fonte
rm !(myfile.txt)
remove tudo, inclusive #myfile.txt
shopt -s extglob
primeiro como @ pl1nk apontoushopt -s extglob
e, em seguida,cd /Users/alumno/
e, finalmente,rm -rf !(Applications|Virtualbox*VMs|Downloads|Documents|Desktop|Public|Library)
Leia sobre englobamento estendido aquiSomente:
Ou:
fonte
ls
saída pode se tornar um problema. Veja aqui para informações detalhadas.Torne os arquivos imutáveis. Nem mesmo o root poderá excluí-los.
Todos os outros arquivos foram excluídos.
Eventualmente, você pode redefini-los mutáveis.
fonte
Isso é semelhante ao comentário de @ siwei-shen, mas você precisa da
-o
bandeira para fazer vários padrões. A-o
bandeira significa 'ou'find . -type f -not -name '*ignore1' -o -not -name '*ignore2' | xargs rm
fonte
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:
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.
fonte
Como ninguém ainda mencionou isso, em um caso específico:
(ou apenas
rm $OLD_FILES
)ou
Você pode precisar usar
shopt -s nullglob
se alguns arquivos estiverem lá ou não:sem nullglob,
echo *.sh *.bash
você pode obter "a.sh b.sh * .bash".(Dito tudo isso, eu mesmo prefiro essa resposta , mesmo que ela não funcione no OSX)
fonte
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 *
ourm -r *
.Em seguida, mova os arquivos necessários para o diretório atual.
fonte
Remova tudo, exclua file.name:
fonte