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.
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:
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.
¿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.
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
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
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.
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.
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.
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.
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
Asumiendo que tengo GNU parallel
instalado), he usado esto:
parallel rm -rf dir/{} ::: `ls -f dir/`
y fue lo suficientemente rápido.
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 {} \;
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.
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.
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.
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
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!
ls -1 | xargs rm -rf
debería funcionar dentro de la carpeta principal
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.