Eliminar millones de archivos

38

Tenía un directorio completo con millones de imágenes gif. Demasiados para el comando rm.

He estado probando el comando find así:

find . -name "*.gif" -print0 | xargs -0 rm

El problema es que bloquea mi máquina realmente mal y causa tiempos de espera para los clientes, ya que es un servidor.

¿Hay alguna forma que sea más rápida de eliminar todos estos archivos ... sin bloquear la máquina?

Corepuncher
fuente
Estoy a una velocidad de eliminación de aproximadamente 6 gb / h usando el comando "nice find" a continuación. Probablemente tomará 48 horas seguidas para deshacerme de todos los archivos. La razón por la que esto sucedió fue que la secuencia de comandos b / ca falló. Había superado el "horizonte de eventos" con comando rm, luego se escapó.
3
¿Eliminar todo el directorio no sería sustancialmente más rápido? Solo saque los archivos "buenos" antes de eliminar los restantes ...
tucuxi
Bueno, cada archivo está mal en este momento, porque se movió a / dir_old, y rehice el / dir. ¿Pero no ejecutará rmdir la misma limitación que rm *?
@Corepuncher: Yo esperaría que la eliminación de todo el directorio (como con rm -rfsería más rápido Vale la pena intentarlo..
Jason R
Actualmente estoy ejecutando "rm -rf" en el directorio. Se ha estado ejecutando durante más de 20 minutos ahora ... todavía no hay cambios en el tamaño del disco. Pero tampoco devolvió automáticamente la "lista de argumentos demasiado larga". El único problema es que realmente está martillando mi máquina y haciendo que otras cosas sean lentas / fallan. No estoy seguro de cuánto tiempo dejarlo ir.

Respuestas:

44

Más rápido no es necesariamente lo que quieres. Es posible que desee ejecutar más lentamente , por lo que la eliminación consume menos recursos mientras se ejecuta.

Use nice (1) para reducir la prioridad de un comando.

nice find . -name "*.gif" -delete

Para los procesos vinculados a E / S, nice (1) podría no ser suficiente. El planificador de Linux tiene en cuenta las E / S, no solo la CPU, sino que es posible que desee un control más preciso sobre la prioridad de E / S.

ionice -c 2 -n 7 find . -name "*.gif" -delete

Si eso no lo hace, también puede agregar un sueño para realmente ralentizarlo.

find . -name "*.gif" -exec sleep 0.01 \; -delete
John Kugelman
fuente
3
wow ... millones de archivos con una suspensión de .1 s ... necesita un día para 864000 archivos.
glglgl
77
@glglgl Muy bien, asno inteligente. Cambié el tiempo de espera. :-P
John Kugelman
28
La suspensión puede ser una buena opción, pero agradable no lo hará, ya que la tarea aquí está vinculada a IO, no a CPU; puedes probar ionice en su lugar. Tenga en cuenta que si el sueño es demasiado pequeño, será inútil.
Matteo Italia
3
@glglgl: el punto es exactamente que si no desea causar una interrupción del servicio en el servidor, debe ir lentamente, el momento en que este código se detiene es para permitir que el servidor haga un trabajo realmente útil con el disco.
Matteo Italia
1
+1 por la sleepadición: estaba teniendo problemas con los servidores que se ahogaban en el IO a pesar de usarlo ionice -c 3. Se agrega significativamente al tiempo que lleva borrar los archivos (por supuesto), pero prefiero esperar antes de cerrar la aplicación ...
Ola Tuvesson
22

Como está ejecutando Linux y esta tarea probablemente esté vinculada a E / S, le aconsejo que otorgue a su comando prioridad de programación de E / S inactiva mediante ionice(1):

ionice -c3 find . -name '*.gif' -delete

En comparación con su comando original, supongo que esto incluso puede ahorrar más ciclos de CPU al evitar la tubería xargs.


fuente
@Braiam ¿Qué quieres decir? Este no es un lugar find ... -execdonde eso tendría sentido.
Oh si, lo siento. Culpa mía. ¿Estás seguro de que es eficiente, aunque?
Braiam el
1
Bueno, la find(1)documentación dice que sí. :) Y debería ser obvio que permitirse findeliminar archivos es más eficiente que bifurcar un rmcomando para esto.
1
He probado varias versiones sugeridas en una carpeta con 4 millones de archivos en un servidor de producción y esta es la única que no bloquea el sistema. ionice -c3baja el prio para que simplemente se ejecute cuando el IO está inactivo, de lo contrario, esto es perfecto. Tenga en cuenta que, dado que -deleteno es estándar para la búsqueda, puede hacer lo mismo (incluida la retroalimentación de que funciona) con este comando: ionice -c 3 find . -name '*.gif' -exec echo {} \; -exec rm {} \;- Lento pero sin espera de procesos importantes.
Christopher Lörken
13

No.

No hay una forma más rápida, aparte del formato suave del disco. Los archivos se entregan a rm a la vez (hasta el límite de la línea de comando, también se puede establecer en xargs), lo cual es mucho mejor que llamar a rm en cada archivo. Entonces no, definitivamente no hay una forma más rápida.

El uso nice(o reniceen un proceso en ejecución) ayuda solo parcialmente, porque eso es para programar el recurso de la CPU , ¡no el disco! Y el uso de la CPU será muy bajo. Esta es una debilidad de Linux: si un proceso "come" el disco (es decir, funciona mucho con él), toda la máquina se atasca. El kernel modificado para uso en tiempo real podría ser una solución.

Lo que haría en el servidor es permitir manualmente que otros procesos hagan su trabajo, incluidas pausas para mantener el servidor "respirando":

find . -name "*.gif" > files
split -l 100 files files.
for F in files.* do
    cat $F | xargs rm
    sleep 5 
done

Esto esperará 5 segundos después de cada 100 archivos. Tomará mucho más tiempo, pero sus clientes no deberían notar demoras.

Tomás
fuente
"Los archivos se entregan a rm a la vez (hasta el límite de la línea de comando", por lo que cuando se ordena el shell rm *, se expande *en la línea con todos los nombres de archivo y se los pasa rm? Eso es increíblemente estúpido. ¿Por qué shell expand comodines?
:-D @Joker_vD, ¿estás bromeando, como sugiere tu nombre? :-)
Tomás
2
@Joker_vD: Compatibilidad con una decisión de Unix de 1970 más o menos. Windows no lo hace. Allí, los programas pueden pasar comodines a FindNextFile / FindNextFile, por lo que obtienen los resultados de uno en uno.
MSalters
@Tomas No en este caso. Honestamente, puedo ver 2 problemas con tal diseño de inmediato: primero, la línea de comando no es de goma; segundo, el programa no puede decir si fue llamado con *o /*y dar una duda a dicha decisión del usuario.
1
@Joker_vD Hay muchas cosas buenas sobre el shell que hace la expansión comodín. Es diferente de Windows, pero no llegues a la conclusión de que es increíblemente estúpido simplemente porque es diferente de lo que estás acostumbrado. Si quieres saber más, te animo a que lo busques en Google o publiques una pregunta en el sitio relevante de Stack Exchange. Es un gran descarrilamiento para esta área de comentarios.
John Kugelman
5

Si la cantidad de archivos que se van a eliminar supera ampliamente a los archivos que quedan, puede que no sea el enfoque más eficiente para recorrer el árbol de archivos que se eliminarán y hacer todas esas actualizaciones del sistema de archivos. (Es análogo a hacer torpe gestión de memoria contada por referencia, visitar cada objeto en un árbol grande para soltar su referencia, en lugar de hacer que todo lo no deseado se convierta en basura en un solo paso, y luego barrer lo que es accesible para limpiar).

Es decir, clonar las partes del árbol que se deben mantener en otro volumen. Vuelva a crear un sistema de archivos nuevo y en blanco en el volumen original. Copie los archivos retenidos a sus rutas originales. Esto es vagamente similar a copiar la recolección de basura .

Habrá algún tiempo de inactividad, pero podría ser mejor que el mal desempeño continuo y la interrupción del servicio.

Puede ser poco práctico en su sistema y situación, pero es fácil imaginar casos obvios en los que este es el camino a seguir.

Por ejemplo, suponga que desea eliminar todos los archivos en un sistema de archivos. ¿Cuál sería el punto de recurrir y eliminar uno por uno? Simplemente desmóntalo y haz un "mkfs" sobre la partición para crear un sistema de archivos en blanco.

¿O suponga que desea eliminar todos los archivos, excepto media docena de archivos importantes? Saca la media docena de allí y ... "mkfs" por encima.

Eventualmente, hay un punto de equilibrio cuando hay suficientes archivos que deben permanecer, que se vuelve más barato hacer la eliminación recursiva, teniendo en cuenta otros costos como cualquier tiempo de inactividad.

Kaz
fuente
4

Has probado:

find . -name "*.gif" -exec rm {} +

El signo + al final hará que find incluya más archivos para que se ejecute el único comando rm. Revise esta pregunta para más detalles.

Bartosz Firyn
fuente
Se ejecuta mucho más rápido que -print0 | Solución xargs porque el proceso rm no se invoca para cada archivo sino para un conjunto grande de ellos y, por lo tanto, está causando una menor carga.
@JohnKugelman Tienes razón, pero es una extensión GNU que no siempre está disponible con el comando de búsqueda nativo .
CodeGnome el
OK, interesante, pero esto es algo bastante nuevo (así como -delete) que no siempre tiene que estar allí ...
Tomás
Sin embargo, esto ciertamente no aporta nada mejor en comparación con la solución del OP.
Tomás el