Elimine eficientemente el directorio grande que contiene miles de archivos


162

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 el rendimiento rm -rfdevuelve 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.


17
rm -rf *en la carpeta probablemente falla debido a demasiados argumentos; pero, ¿qué pasa rm -rf folder/si quieres eliminar todo el directorio de todos modos?
sr_

44
En lugar de eliminarlo manualmente, sugiero tener la carpeta en una partición separada y simplemente desmontar && format && remontar.
bbaja42

77
Solo por curiosidad: ¿cuántos archivos se necesitan para romper rm -rf?
jw013

77
Probablemente debería cambiar el nombre de la pregunta a algo más preciso, como "Eliminar eficientemente un directorio grande que contenga miles de archivos". Para eliminar un directorio y su contenido, la recursión es necesaria por definición. Puede desvincular manualmente solo el inodo del directorio (probablemente requiere privilegios de root), desmontar el sistema de archivos y ejecutarlo fsckpara recuperar los bloques de disco no utilizados, pero ese enfoque parece arriesgado y puede que no sea más rápido. Además, la verificación del sistema de archivos puede implicar atravesar recursivamente el árbol del sistema de archivos de todos modos.
jw013

44
Una vez que tuve un ccacheárbol de archivos tan grande, y me rmtomó tanto tiempo (y haciendo que todo el sistema se volviera lento), fue considerablemente más rápido copiar todos los demás archivos del sistema de archivos, formatearlos y copiarlos de nuevo. Desde entonces, le doy a estos enormes árboles de archivos pequeños su propio sistema de archivos dedicado, para que pueda mkfshacerlo directamente en lugar de hacerlo rm.
frostschutz

Respuestas:


213

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

44
Gracias muy útil Uso rsync todo el tiempo, no tenía idea de que podría usarlo para eliminar de esta manera. Bastante más rápido que rm -rf
John Powell

22
rsyncpuede ser más rápido que simple rm, ya que garantiza las eliminaciones en el orden correcto, por lo que se necesita menos recálculo de btress. Ver esta respuesta serverfault.com/a/328305/105902
Marki555

77
¿Alguien puede modificar la expresión perl para eliminar recursivamente todos los directorios y archivos dentro de un directorio_to_be_deletado ?
Abhinav

55
Notas: agregue la -Popción a rsync para una visualización más, también, tenga cuidado con la sintaxis, las barras diagonales son obligatorias. Finalmente, puede iniciar el comando rsync por primera vez con la -nopción primero de iniciar una ejecución en seco .
Drasill

1
-aigual -rlptgoD, pero solo para borrar -rdes necesario
Koen.

39

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

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


11
Esto no es estándar. GNU findtiene -delete, y findtal vez otros .
enzotib

14
-deletesiempre se debe preferir a -exec rmcuando esté disponible, por razones de seguridad y eficiencia.
jw013

66
GNU es el estándar de facto .
RonJohn

17

¿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 a la vez cambiando el argumento para el parámetro -n. También se incluyen los nombres de archivo con espacios en blanco.


2
Probablemente no necesite el -n 20bit, ya que xargs debería limitarse a tamaños aceptables de listas de argumentos de todos modos.
Inútil

Sí, tiene usted razón. Aquí hay una nota de man xargs: (...) max-chars characters per command line (...). The largest allowed value is system-dependent, and is calculated as the argument length limit for exec. Entonces, la -nopción es para aquellos casos en los que xargs no puede determinar el tamaño del búfer de la CLI o si el comando ejecutado tiene algunos límites.
digital_infinity

12

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 el trabajo:

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

66
Esta es la única solución que funcionó: ejecutar rm -Rf bigdirectoryvarias veces. Tenía un directorio con miles de millones de subdirectorios y archivos. Ni siquiera podía correr lso findo rsyncen ese directorio, ya que se quedó sin memoria. El comando se rm -Rfcerró muchas veces (sin memoria) solo eliminando parte de los miles de millones de archivos. Pero después de muchos intentos, finalmente hizo el trabajo. Parece ser la única solución si el problema es quedarse sin memoria.
erik

12

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


No es tan rápido, porque lee el contenido del directorio de manera eficiente. Consulte esta respuesta para obtener una solución y explicación 10 veces más rápida serverfault.com/a/328305/105902
Marki555

2
@ Marki555: en la edición de la pregunta se informa 60 segundos para rsync -a --deletevs 43 para lsdent. La relación 10x fue para time ls -1 | wc -l vs time ./dentls bigfolder >out.txt(que es una comparación parcialmente justa debido a > filevs wc -l).
Hastur

El problema es que NINGUNO de los comandos allí realmente HACE la operación transversal deseada para su eliminación. ¿El código que dan? NO FUNCIONA como lo describe Marki555.
Svartalf

6

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

El uso -deleteeliminó 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.


3
El uso find -execejecuta el rmcomando para cada archivo por separado, por eso es tan lento.
Marki555

5

Acerca de la -deleteopción anterior: la 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 es EXTREMADAMENTE gravar en la CPU que el otro comando no. Se ha estado ejecutando 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 funcionando ( uptimeinformes):

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.


si va a usarlo, execes casi seguro que no quiere usar -lsy do find . -type f -exec rm '{}' ++ es más rápido porque le dará tantos argumentos a rm como pueda manejar a la vez.
xenoterracide

Creo que deberías seguir adelante y editar esto en su propia respuesta ... es realmente demasiado largo para un comentario. Además, parece que su sistema de archivos tiene eliminaciones bastante caras, ¿tiene curiosidad por saber cuál es? Puede ejecutar eso a find … -deletetravés de niceo ionice, eso puede ayudar. Por lo tanto, podría cambiar algunas opciones de montaje a configuraciones menos seguras contra choques. (Y, por supuesto, dependiendo de qué más hay en el sistema de archivos, la forma más rápida de eliminar todo es a menudo mkfs.)
derobert

3
El promedio de carga no siempre es CPU, es solo una medida del número de procesos bloqueados a lo largo del tiempo. Los procesos pueden bloquear la E / S del disco, que probablemente sea lo que está sucediendo aquí.
Score_Under

También tenga en cuenta que el promedio de carga no tiene en cuenta el número de CPU lógicas. Entonces, cargar la máquina 1de un solo núcleo es lo mismo que cargar 64en el sistema de 64 núcleos, lo que significa que cada CPU está ocupada el 100% del tiempo.
Marki555


3

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 y luego desmontar y eliminar su archivo para eliminar todo a la vez realmente rápido.


2

Suponiendo que tengo GNU parallelinstalado, he usado esto:

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

Y fue lo suficientemente rápido.


2

Usar en rm -rf directorylugar de rm -rf *.

Inicialmente estábamos haciendo rm -rf *mientras estábamos en el directorio para borrar el contenido y pensamos 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, pasemos al 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 de uso 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 directoryes aproximadamente 9 VECES MÁS RÁPIDO que rm -rf *!

No hace falta decir que le compramos cerveza a ese ingeniero .

Así que ahora usamos rm -rf directory; mkdir directorypara eliminar el directorio y volver a crearlo.


1

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-time para ello. La carga de sus sistemas no se elevará a un nivel alto y todo permanece receptivo (aunque el tiempo de mi CPU para encontrar fue bastante alto, aproximadamente el 50%).

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

55
usar en +lugar de \;lo haría más rápido, ya que pasa más argumentos a la rm a la vez, menos bifurcación
xenoterracide

1
¿Por qué no? ionice -c3 find <dir> -type f -delete
jtgd

1

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=("$@")
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 se los pasará nice_delete. Esto creará lotes aún más pequeños para permitir dormir cuando se detecta sobrecarga.


0
ls -1 | xargs rm -rf 

debería funcionar dentro de la carpeta principal


1
lsno funcionará debido a la cantidad de archivos en la carpeta. Es por eso que tuve que usar find, gracias.
Toby

44
@Toby: Probar ls -f, que deshabilita la ordenación. La ordenación requiere que todo el directorio se cargue en la memoria para ser ordenado. Un no clasificado lsdebe poder transmitir su salida.
camh

1
No funciona en nombres de archivo que contienen nuevas líneas.
maxschlepzig

@camh eso es cierto. Pero eliminar archivos en orden ordenado es más rápido que en no ordenado (debido a recalcular el btree del directorio después de cada eliminación). Consulte esta respuesta para ver un ejemplo serverfault.com/a/328305/105902
Marki555

@maxschlepzig para dichos archivos que puede usar find . -print0 | xargs -0 rm, que usarán el carácter NULL como separador de nombre de archivo.
Marki555

0

Para la pista de Izkata arriba:

Pero esto hace el trabajo:

$ 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

Dependiendo de qué tan bien necesita deshacerse de esos archivos, sugeriría usarlos 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.


1
shred no funcionará con muchos sistemas de archivos modernos.

0

Si solo desea deshacerse de muchos archivos lo antes posible, ls -f1 /path/to/folder/with/many/files/ | xargs rmpodría funcionar bien, pero mejor no lo ejecute en sistemas de producción porque su sistema podría convertirse en problemas de E / S 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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.