desenv-web-rp.com

Exclua com eficiência o diretório grande que contém milhares de arquivos

Temos um problema com uma pasta que se torna pesada com centenas de milhares de arquivos minúsculos.

Existem tantos arquivos que executam rm -rf retorna um erro e, em vez disso, o que precisamos fazer é algo como:

find /path/to/folder -name "filenamestart*" -type f -exec rm -f {} \;

Isso funciona, mas é muito lento e constantemente falha ao ficar sem memória.

Existe uma maneira melhor de fazer isso? Idealmente, eu gostaria de remover o diretório inteiro sem me preocupar com o conteúdo dele.

177
Toby

Usar o rsync é surpreendente, rápido e simples.

mkdir empty_dir
rsync -a --delete empty_dir/    yourdirectory/

A resposta de @ sarath mencionou outra opção rápida: Perl! Seus benchmarks são mais rápidos que rsync -a --delete.

cd yourdirectory
Perl -e 'for(<*>){((stat)[9]<(unlink))}'

Fontes:

  1. https://stackoverflow.com/questions/1795370/unix-fast-remove-directory-for-cleaning-up-daily-builds
  2. http://www.slashroot.in/which-is-the-fastest-method-to-delete-files-in-linux
238
stevendaniels

Alguém em Twitter sugeriu o uso de -delete ao invés de -exec rm -f{} \;

Isso melhorou a eficiência do comando, mas ainda usa recursão para passar por tudo.

42
Toby

Que tal algo como: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Você pode limitar o número de arquivos a serem excluídos de uma só vez, alterando o argumento do parâmetro -n. Os nomes dos arquivos com espaços em branco também estão incluídos.

19
digital_infinity

Um truque inteligente:

rsync -a --delete empty/ your_folder/

É super intensivo em CPU, mas realmente muito rápido. Veja https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files .html

16
MZAweb

Expandindo um dos comentários, não acho que você esteja fazendo o que pensa.

Primeiro, criei uma enorme quantidade de arquivos para simular sua situação:

$ mkdir foo
$ cd foo/
$ for X in $(seq 1 1000);do touch {1..1000}_$X; done

Depois, tentei o que esperava falhar e o que parece que você está fazendo na pergunta:

$ rm -r foo/*
bash: /bin/rm: Argument list too long

Mas isso funciona funciona:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory
14
Izkata

Eu tive a oportunidade de testar -delete em comparação com -exec rm \{\} \; e para mim -delete foi a resposta para esse problema.

Usando -delete excluiu os arquivos em uma pasta de 400.000 arquivos pelo menos 1.000 vezes mais rápido que rm.

O artigo 'Como excluir um grande número de arquivos no linux' sugere que é cerca de três vezes mais rápido, mas no meu teste a diferença foi muito mais dramática.

10
user2365090

Sobre a -delete opção acima: estou usando-o para remover um grande número de arquivos (1M + est) em uma pasta temporária que eu criei e esqueci inadvertidamente a limpeza noturna. Enchi meu disco/partição acidentalmente e nada mais poderia removê-los, exceto o find . comando. É lento, no começo eu estava usando:

find . -ls -exec rm {} \;

Mas isso levou um tempo EXTREMO. Ele foi iniciado após cerca de 15 minutos para remover alguns arquivos, mas meu palpite é que ele estava removendo menos de 10 ou mais por segundo depois que finalmente foi iniciado. Então, eu tentei o:

find . -delete

em vez disso, e eu estou deixando isso funcionar agora. Parece estar rodando mais rápido, apesar de estar EXTREMAMENTE sobrecarregando a CPU, o que o outro comando não estava. Está em execução há mais de uma hora e acho que estou recuperando espaço na minha unidade e a partição gradualmente "diminuindo", mas ainda está demorando muito tempo. Eu duvido seriamente que esteja rodando 1.000 vezes mais rápido que o outro. Como em todas as coisas, eu só queria apontar a troca no espaço versus tempo. Se você tiver a largura de banda da CPU de sobra (temos), execute a última. A minha CPU está funcionando (uptime reports):

10:59:17 up 539 days, 21:21,  3 users,  load average: 22.98, 24.10, 22.87

E eu já vi a média de carga ultrapassar 30,00, o que não é bom para um sistema ocupado, mas para o nosso, que normalmente é carregado com pouca carga, fica bom por algumas horas. Eu verifiquei a maioria das outras coisas no sistema e elas ainda respondem, por isso estamos bem por enquanto.

5
Scotty

Considere usar o volume Btrfs e simplesmente exclua o volume inteiro desse diretório com grande número de arquivos.

Como alternativa, você pode criar um arquivo de imagem FS, em seguida, desmonte e exclua o arquivo para remover tudo de uma só vez muito rápido.

4
Sergei

Usar rm -rf directory ao invés de rm -rf *.

Inicialmente estávamos fazendo rm -rf * enquanto estava no diretório para limpar o conteúdo e achou que era o mais rápido possível. Mas então um de nossos engenheiros seniores sugeriu que evitássemos usar asteriscos (*) e, em vez disso, passe no diretório pai, como rm -rf directory.

Após um intenso debate sobre como isso não faria diferença, decidimos compará-lo, juntamente com um terceiro método de usar find. Aqui estão os resultados:

time rm -rf *                   2m17.32s
time rm -rf directory           0m15.60s
time find directory -delete     0m16.97s

rm -rf directory é cerca de 9 vezes mais rápido que rm -rf *!

Escusado será dizer que compramos esse engenheiro uma cerveja!

Então agora usamos rm -rf directory; mkdir directory para excluir o diretório e recriá-lo.

4
Joshua Pinter

Existem alguns métodos que podem ser usados ​​para excluir um grande número de arquivos no linux. Você pode usar a opção find with delete, que é mais rápida que a opção exec. Então você pode usar o Perl unlink e até o rsync. Como excluir um grande número de arquivos no linux

4
sarath

Supondo que você tenha GNU parallel instalado, eu usei isso:

parallel rm -rf dir/{} ::: `ls -f dir/`

e foi rápido o suficiente.

2
Nacho

A exclusão de diretórios REALMENTE GRANDES precisa de uma abordagem diferente, como aprendi em este site - você precisará utilizar o ionice. tempo para isso. A carga do seu sistema não aumentará muito e tudo permanecerá responsivo (embora o tempo de busca da CPU tenha sido bastante alto em cerca de 50%).

find <dir> -type f -exec ionice -c3 rm {} \;
1
gamma

Se você possui milhões de arquivos e todas as soluções acima colocam seu sistema em estresse, tente esta inspiração:

Arquivo Nice_delete:

#!/bin/bash

MAX_LOAD=3
FILES=("[email protected]")
BATCH=100

while [ ${#FILES[@]} -gt 0 ]; do
    DEL=("${FILES[@]:0:$BATCH}")
    ionice -c3 rm "${DEL[@]}"
    echo -n "#"
    FILES=("${FILES[@]:$BATCH}")
    while [[ $(cat /proc/loadavg | awk '{print int($1)}') -gt $MAX_LOAD ]]; do
        echo -n "."
        sleep 1
    done
done

E agora exclua os arquivos:

find /path/to/folder -type f -exec ./Nice_delete {} \+

A localização criará lotes (consulte getconf ARG_MAX) de algumas dezenas de milhares de arquivos e passá-lo para Nice_delete. Isso criará lotes ainda menores para permitir suspensão quando a sobrecarga for detectada.

1
brablc

Dependendo de quão bem você precise se livrar desses arquivos, sugiro usar shred.

$ shred -zuv folder

se você deseja limpar o diretório, mas não pode removê-lo e recriá-lo, sugiro movê-lo e recriá-lo instantaneamente.

mv folder folder_del
mkdir folder
rm -rf folder_del

isso é mais rápido, acredite ou não, pois apenas um inode deve ser alterado. Lembre-se: você realmente não pode paralelizar essa prova em um computador com vários núcleos. Tudo se resume ao acesso ao disco, limitado pelo RAID ou pelo que você possui.

0
polemon

Os scripts Python não devem ser evitados como impuros:

#!/usr/bin/python3

import shutil
path_for_deletion = input( 'path of dir for deletion> ' ) 
print( 'about to remove ' + path_for_deletion + ' ...' )
shutil.rmtree( path_for_deletion, ignore_errors=True )
print( '... done' )

Eu perguntei ao cara que fez alguns testes comparativos úteis de vários métodos aqui se ele poderia tentar fazer testes comparativos. Pelas minhas experiências, parece muito bom.

Os erros de NB podem ser manipulados para pelo menos imprimi-los ... mas pode ser mais simples de executar trash myDirectoryForDeletion ou rm -rfv myDirectoryForDeletion mais tarde.

0
mike rodent

Se você quiser se livrar de muitos arquivos o mais rápido possível, ls -f1 /path/to/folder/with/many/files/ | xargs rm Pode funcionar bem, mas é melhor não executá-lo em sistemas de produção, porque seu sistema pode se tornar IO problemas e aplicativos podem ficar presos durante a operação de exclusão.

Esse script funciona bem para muitos arquivos e não deve afetar o ioload do sistema.

#!/bin/bash

# Path to folder with many files
FOLDER="/path/to/folder/with/many/files"

# Temporary file to store file names
FILE_FILENAMES="/tmp/filenames"

if [ -z "$FOLDER" ]; then
    echo "Prevented you from deleting everything! Correct your FOLDER variable!"
    exit 1
fi

while true; do
    FILES=$(ls -f1 $FOLDER | wc -l)
    if [ "$FILES" -gt 10000 ]; then
        printf "[%s] %s files found. going on with removing\n" "$(date)" "$FILES"
        # Create new list of files
        ls -f1 $FOLDER | head -n 5002 | tail -n 5000 > "$FILE_FILENAMES"

        if [ -s $FILE_FILENAMES ]; then
            while read FILE; do
                rm "$FOLDER/$FILE"
                sleep 0.005
            done < "$FILE_FILENAMES"
        fi
    else
        printf "[%s] script has finished, almost all files have been deleted" "$(date)"
        break
    fi
    sleep 5
done
0
Leon Kramer

Para a dica de Izkata acima:

Mas isso funciona :

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

Isso quase funcionou - ou teria funcionado - mas eu tive alguns problemas de permissão; os arquivos estavam em um servidor, mas ainda não entendo de onde veio esse problema de permissão. De qualquer forma, o Terminal pediu confirmação em todos os arquivos. A quantidade de arquivos era de cerca de 20 000, portanto não era uma opção. Depois de "-r", adicionei a opção "-f", então todo o comando foi "rm -r -f nome da pasta / = ". Então pareceu funcionar bem. Sou iniciante no Terminal, mas acho que tudo bem, certo? Obrigado!

0
user41527
ls -1 | xargs rm -rf 

deve funcionar dentro da pasta principal

0
PsyStyle

Use ls -f | xargs -n 5000 rm, Enquanto ajusta -n Para o tamanho do lote, conforme apropriado ao seu sistema (parabéns a @digital_infinity pela dica -n).

Além disso, você pode filtrar a lista com um grep embutido, por exemplo ls -f | grep '^156' | xargs -n 5000 rm.

Na minha experiência, isso é muito mais rápido do que as técnicas usando find e evita a necessidade de scripts Shell mais complexos.

0
buckaroo1177125