desarrollo-web-br-bd.com

Elimine eficientemente el directorio grande que contiene miles de archivos

Tenemos un problema con una carpeta que se vuelve difícil de manejar con cientos de miles de archivos pequeños.

Hay tantos archivos que realizan rm -rf devuelve un error y, en cambio, lo que debemos hacer es algo como:

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

Esto funciona pero es muy lento y falla constantemente por quedarse sin memoria.

¿Hay una mejor manera de hacer esto? Idealmente, me gustaría eliminar todo el directorio sin preocuparme por el contenido que contiene.

177
Toby

Usar rsync es sorprendentemente rápido y simple.

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

La respuesta de @ sarath mencionó otra opción rápida: ¡Perl! Sus puntos de referencia son más rápidos que rsync -a --delete.

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

Fuentes:

  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

Alguien en Twitter sugirió usar -delete en lugar de -exec rm -f{} \;

Esto ha mejorado la eficiencia del comando, aunque todavía usa la recursividad para pasar por todo.

42
Toby

¿Qué pasa con algo como: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

Puede limitar el número de archivos para eliminar de una vez cambiando el argumento del parámetro -n. También se incluyen los nombres de archivo con espacios en blanco.

19
digital_infinity

Un truco inteligente:

rsync -a --delete empty/ your_folder/

Es súper intensivo en CPU, pero realmente muy rápido. Ver https://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files .html

16
MZAweb

Ampliando uno de los comentarios, no creo que estés haciendo lo que crees que estás haciendo.

Primero creé una gran cantidad de archivos, para simular su situación:

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

Luego probé lo que esperaba que fallara, y lo que parece que estás haciendo en la pregunta:

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

Pero esto hace trabajo:

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

Tuve la oportunidad de probar -delete en comparación con -exec rm \{\} \; y para mí -delete fue la respuesta a este problema.

Utilizando -delete eliminó los archivos en una carpeta de 400,000 archivos al menos 1,000 veces más rápido que rm.

El artículo 'Cómo eliminar una gran cantidad de archivos en Linux' sugiere que es aproximadamente tres veces más rápido, pero en mi prueba la diferencia fue mucho más dramática.

10
user2365090

Acerca de -delete opción anterior: lo estoy usando para eliminar una gran cantidad (1M + est) de archivos en una carpeta temporal que creé y, sin querer, olvidé limpiar todas las noches. Llené mi disco/partición accidentalmente, y nada más podría eliminarlos excepto el find . comando. Es lento, al principio estaba usando:

find . -ls -exec rm {} \;

Pero eso estaba tomando una cantidad EXTREMA de tiempo. Comenzó después de unos 15 minutos para eliminar algunos de los archivos, pero supongo que estaba eliminando menos de 10 por segundo después de que finalmente comenzó. Entonces, probé el:

find . -delete

en cambio, y lo dejo correr ahora mismo. Parece que se está ejecutando más rápido, aunque grava EXTREMADAMENTE en la CPU lo que no era el otro comando. Ha estado funcionando durante aproximadamente una hora y creo que estoy recuperando espacio en mi disco y la partición gradualmente se "adelgaza", pero todavía está tomando mucho tiempo. Dudo seriamente que funcione 1,000 veces más rápido que el otro. Como en todas las cosas, solo quería señalar la compensación en el espacio frente al tiempo. Si tiene el ancho de banda de la CPU de sobra (lo hacemos), ejecute el último. Tiene mi CPU en funcionamiento (uptime informes):

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

Y he visto que el promedio de carga supera los 30.00, lo que no es bueno para un sistema ocupado, pero para el nuestro, que normalmente está ligeramente cargado, está bien durante un par de horas. He revisado la mayoría de las otras cosas en el sistema y todavía responden, así que estamos bien por ahora.

5
Scotty

Considere usar el volumen Btrfs y simplemente elimine todo el volumen para dicho directorio con una gran cantidad de archivos.

Alternativamente, puede crear un archivo de imagen FS) luego desmontar y eliminar su archivo para eliminar todo a la vez realmente rápido.

4
Sergei

Utilizar rm -rf directory en lugar de rm -rf *.

Inicialmente estábamos haciendo rm -rf * mientras estaba en el directorio para borrar el contenido y pensó que era lo más rápido posible. Pero entonces uno de nuestros ingenieros superiores sugirió que evitemos usar los asteriscos (*) y en su lugar pasa en el directorio principal, como rm -rf directory.

Después de un intenso debate sobre cómo eso no haría una diferencia, decidimos compararlo, junto con un tercer método para usar find. Aquí están los resultados:

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

rm -rf directory es aproximadamente 9 VECES MÁS RÁPIDO que rm -rf *!

No hace falta decir que compramos ese ingeniero una cerveza!

Entonces ahora usamos rm -rf directory; mkdir directory para eliminar el directorio y volver a crearlo.

4
Joshua Pinter

Hay un par de métodos que se pueden usar para eliminar una gran cantidad de archivos en Linux. Puede usar la opción buscar con eliminar, que es más rápida que la opción exec. Luego puede usar Perl Unlink, e incluso rsync. Cómo eliminar una gran cantidad de archivos en Linux

4
sarath

Asumiendo que tengo GNU parallel instalado), he usado esto:

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

y fue lo suficientemente rápido.

2
Nacho

La eliminación de directorios REALMENTE GRANDES necesita un enfoque diferente, como aprendí de este sitio - necesitará utilizar ionice. Asegura (con -c3) que las eliminaciones solo se realizarán cuando el sistema tenga IO- tiempo para eso. La carga de sus sistemas no se elevará a un nivel alto y todo permanecerá receptivo (aunque el tiempo de mi CPU para encontrar fue bastante alto, aproximadamente el 50%).

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

Si tiene millones de archivos y todas las soluciones anteriores ponen su sistema en tensión, puede probar esta inspiración:

Archivo 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

Y ahora borre los archivos:

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

Buscar creará lotes (ver getconf ARG_MAX) de unas decenas de miles de archivos y pasarlo a Nice_delete. Esto creará lotes aún más pequeños para permitir dormir cuando se detecta sobrecarga.

1
brablc

Dependiendo de qué tan bien necesita deshacerse de esos archivos, sugeriría usar shred.

$ shred -zuv folder

si desea purgar el directorio, pero no puede eliminarlo y volver a crearlo, le sugiero moverlo y volver a crearlo al instante.

mv folder folder_del
mkdir folder
rm -rf folder_del

esto es más rápido, lo creas o no, ya que solo hay que cambiar un inodo. Recuerde: Realmente no puede paralelizar este sabor en una computadora multinúcleo. Todo se reduce al acceso al disco, que está limitado por el RAID o lo que tienes.

0
polemon

Las secuencias de comandos de Python no deben evitarse como impuras:

#!/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' )

Le pregunté al tipo que ha realizado algunas evaluaciones comparativas útiles de varios métodos aquí si podría intentar evaluar esto. De mis experimentos parece bastante bueno.

Los errores de NB podrían manejarse al menos para imprimirlos ... pero podría ser más simple ejecutar trash myDirectoryForDeletion o rm -rfv myDirectoryForDeletion después.

0
mike rodent

Si solo quiere deshacerse de muchos archivos lo antes posible ls -f1 /path/to/folder/with/many/files/ | xargs rm podría funcionar bien, pero mejor no lo ejecute en sistemas de producción porque su sistema podría convertirse en problemas IO) y las aplicaciones podrían bloquearse durante la operación de eliminación.

Este script funciona bien para muchos archivos y no debería afectar la carga del 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 la pista de Izkata arriba:

Pero esto funciona :

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

Esto casi funcionó, o habría funcionado, pero tuve algunos problemas con el permiso; los archivos estaban en un servidor, pero aún no entiendo de dónde vino este problema de permiso. De todos modos, Terminal solicitó confirmación en cada archivo. La cantidad de archivos rondaba los 20 000, por lo que esta no era una opción. Después de "-r" agregué la opción "-f", por lo que todo el comando fue "rm -r -f foldername / = ". Entonces pareció funcionar bien. Soy un novato con Terminal, pero supongo que esto estuvo bien, ¿verdad? ¡Gracias!

0
user41527
ls -1 | xargs rm -rf 

debería funcionar dentro de la carpeta principal

0
PsyStyle

Utilizar ls -f | xargs -n 5000 rm, mientras ajusta el -n para el tamaño de lote según corresponda a su sistema (felicitaciones a @digital_infinity para -n propina).

Además, puede filtrar la lista con un grep en línea, p. ls -f | grep '^156' | xargs -n 5000 rm.

En mi experiencia, esto es mucho más rápido que las técnicas que usan find y obvia la necesidad de scripts de Shell más complejos.

0
buckaroo1177125