miércoles, 1 de mayo de 2019

-bash: /usr/bin/rm: Argument list too long



Qué provoca el error "-bash: /usr/bin/rm: Argument list too long", cómo borrar muchos, decenas, cientos, miles de archivos con un nombre determinado, de un directorio en Linux.



Antes de ver qué provoca el error "-bash: /usr/bin/rm: Argument list too long", veamos primero cómo se puede llegar a desencadenar la situación que lo origina.

Todo empezó cuando una compañera me comunicó que el acceso por FTP a cierto directorio de un servidor daba problemas. Me conecté por FTP al servidor y vi que, efectivamente, el servidor daba tiemout al tratar de devolver la lista de archivos de un directorio específico:

ftp> cd directorio 250 Directory successfully changed. ftp> dir 200 PORT command successful. Consider using PASV. 150 Here comes the directory listing. Error: Connection timed out Error: Failed to retrieve directory listing

Probé a listar el contenido de ese directorio desde la terminal de Linux para ver qué ocurria. Pasado un minuto aprox., el sistema me devolvió el listado de archivos.


Causas



Me encontré con miles de archivos de unos pocos bytes en el directorio afectado. Deduje entonces que algún programa estaba creando esos archivos cada día a una hora determinada, puesto que su hora de creación era la misma, día tras día.

La presencia de este gran volumen de archivos causaba timeout en el FTP porque al sistema no le daba tiempo a generar y mostrar la lista de archivos del directorio antes de hacer timeout. Del mismo modo, bash demoraba mucho tiempo hasta tener generada la lista de archivos del directorio, por su volumen.


Consecuencias



Mientras otra persona buscaba qué aplicación estaba creando esos archivos, tuve que lidiar con la posibilidad de que el disco donde se escribían estos archivos se quedara sin inodos libres, lo cual dejaría KO las aplicaciones que corren sobre él.


Solución



Debía borrar estos archivos. Empecé por buscar patrones compartidos por todos ellos y vi que todos los archivos tenían algo en común: sus nombres eran de 32 caracteres. Esto me daba una posibilidad de borrarlos en masa. Recordemos que, en Linux, para borrar archivos cuyo nombre de archivo es de una longitud determinada, se puede usar rm seguido de tantos ? como caracteres tenga el nombre.

En mi caso:

HOST# rm ???????????????????????????????? -bash: /usr/bin/rm: Argument list too long

El sistema se quejaba de que había demasiados archivos que coincidieran con el patrón facilitado, así que bash no podía ejecutar el comando rm sobre ellos.


Método 1: rm



Probé a ir bajando el número de comodines hasta que el sistema me dejó ejecutar:

HOST# rm 12E0ECTF783B1EE88ADA????????????

Llegados a este punto, podía ir borrando los archivos restantes poco a poco: buscar un nuevo patrón, borrar los archivos que siguen ese patrón, listar los archivos restantes, borrar el siguiente patrón, etc. pero eso era una tarea demasiado manual.

Tras buscar un poco, vi que se podía atacar el problema de otra forma más efectiva.


Método 2: find



Usando el comando find, bash no se queja del número de archivos a procesar.

HOST# find . -type f -name "12E?????????????????????????????" -delete


Resolución



Acabé usando el método 2, find, para borrar de golpe todos los archivos que quería eliminar. Después de esto, el sistema volvió a listar los archivos de esa carpeta de forma habitual (en milisegundos), tanto desde el FTP como desde la terminal. Ahora, el problema era enteramente del desarrollador...


¿Por qué se da el límite de argumentos en bash?



El límite de argumentos del cual se queja bash se da en la función del kernel execve (), que es utilizada por todas las demás funciones exec () (execl, execlp, execle, etc.). Lo que hace esta función es crear un búfer de 128 K en el extremo superior del espacio de memoria y copiar la línea de comandos y el entorno para el nuevo proceso en este espacio. El kernel luego carga el nuevo programa en la memoria, establece sus punteros argv y envp, y salta al punto de entrada del programa. El mensaje de error "Argument list too long" está causado por el código de error !E2BIG, devuelto por la función execve (), cuando no puede encajar la lista de argumentos y el entorno suministrados dentro del búfer de 128K.


Fuentes:

https://wiki.debian.org/CommonErrorMessages/ArgumentListTooLong
https://stackoverflow.com/questions/13409403/delete-files-with-a-length-of-x-or-more-characters
https://superuser.com/questions/701985/linux-how-can-i-delete-all-files-whose-file-name-is-more...
0

0 comentarios:

Publicar un comentario