Tengo varios cientos de archivos PDF en un directorio en UNIX. Los nombres de los archivos PDF son realmente largos (aprox. 60 caracteres).
Cuando intento eliminar todos los archivos PDF juntos usando el siguiente comando:
rm -f *.pdf
Obtuve el siguiente error:
/bin/rm: cannot execute [Argument list too long]
¿Cuál es la solución a este error? ¿Ocurre este error para mvy cpcomandos también? En caso afirmativo, ¿cómo resolver estos comandos?

Respuestas:
La razón por la que esto ocurre es porque bash en realidad expande el asterisco a cada archivo coincidente, produciendo una línea de comando muy larga.
Prueba esto:
Advertencia: esta es una búsqueda recursiva y también encontrará (y eliminará) archivos en subdirectorios. Agregue el
-fcomando rm solo si está seguro de que no desea confirmación.Puede hacer lo siguiente para que el comando no sea recursivo:
Otra opción es usar la
-deletebandera de find :fuente
xargsdivide específicamente la lista y emite varios comandos si es necesario.-maxdepth 1debe ser el primer argumento después del camino.-deletebandera para eliminar los archivos que encuentra, e incluso si no fuera así, se consideraría una mejor práctica usar-execpara ejecutar rm, en lugar de invocar xargs (que ahora son 3 procesos y una tubería en lugar de un solo proceso con-deleteo 2 procesos con-exec).dangerous (broken, exploitable, etc.), es bastante ridículo. Sin duda, debe tener cuidado al usarloxargs, pero no lo es del todoeval/evil.-execllamadarm, el número de procesos será 1 + número de archivos, aunque el número de procesos concurrentes a partir de esto puede ser 2 (quizás find ejecutaría procesos rm simultáneamente). El número de procesosxargsque se usarían se reduciría drásticamente a 2 + n, donde n es un número de procesos menor que el número de archivos (digamos número de archivos / 10, aunque probablemente más dependiendo de la longitud de las rutas). Suponiendo que find realiza la eliminación directamente, usar-deletedebería ser el único proceso que se invocaría.tl; dr
Es una limitación del núcleo en el tamaño del argumento de la línea de comando. Use un
forbucle en su lugar.Origen del problema
Este es un problema del sistema, relacionado
execveyARG_MAXconstante. Hay mucha documentación al respecto (ver man execve , debian's wiki ).Básicamente, la expansión produce un comando (con sus parámetros) que excede el
ARG_MAXlímite. En kernel2.6.23, el límite se estableció en128 kB. Esta constante se ha incrementado y puede obtener su valor ejecutando:Solución: Usando
forLoopUse un
forbucle como se recomienda en BashFAQ / 095 y no hay límite, excepto para RAM / espacio de memoria:La ejecución en seco para determinarlo eliminará lo que espera:
Y ejecutarlo:
Además, este es un enfoque portátil, ya que Glob tiene un comportamiento fuerte y consistente entre los depósitos ( parte de la especificación POSIX ).
Nota: Como se ha señalado en varios comentarios, esto es más lento pero más fácil de mantener, ya que puede adaptar escenarios más complejos, por ejemplo , donde uno quiere hacer más de una sola acción.
Solución: usar
findSi insiste, puede usar
findpero realmente no usar xargs ya que "es peligroso (roto, explotable, etc.) al leer entradas no delimitadas por NUL" :Usar en
-maxdepth 1 ... -deletelugar de-exec rm {} +permitefindsimplemente ejecutar las llamadas del sistema requeridas sin usar un proceso externo, por lo tanto, más rápido (gracias al comentario de @chepner ).Referencias
fuente
forbucle. Lo he usadofindantes, pero siempre estoy buscando cómo hacerlo, ya que olvido las opciones, etc. todo el tiempo.forparece más fácil de recordar en mi humilde opiniónfor f in *; do rm "$f"; donefind -execsolución parece ser MUCHO más rápida que elforciclo.4.15.0-1019-gcppara ser exactos) y el límite todavía está en 2097152. Curiosamente, la búsqueda de ARG_MAX en el repositorio de Linux git da un resultado que muestra que ARG_MAX está en 131702.findtiene una-deleteacción:fuente
xargs, según la respuesta de Dennis, funciona según lo previsto.-execes eliminar un montón de archivos.-exec rm {} +haría lo mismo, pero aún requiere iniciar al menos un proceso externo.-deletepermitefindejecutar simplemente el sistema requerido se llama a sí mismo sin usar un contenedor externo.Otra respuesta es forzar
xargsprocesamiento de los comandos en lotes. Por ejemplo adeletelos archivos100a la vez,cden el directorio y ejecute esto:echo *.pdf | xargs -n 100 rmfuente
echohay un shell incorporado. Si termina usando el comandoecho, aún se encontrará con el límite de argumentos del programa.O puedes probar:
fuente
find . -maxdepth 1 -name '*.pdf' -exec rm -f {} \;Si está tratando de eliminar una gran cantidad de archivos a la vez (eliminé un directorio con más de 485,000 hoy), probablemente se encontrará con este error:
El problema es que cuando escribes algo como
rm -rf *, el*se reemplaza con una lista de todos los archivos coincidentes, como "rm -rf file1 file2 file3 file4" y así sucesivamente. Hay un búfer de memoria relativamente pequeño asignado para almacenar esta lista de argumentos y si se llena, el shell no ejecutará el programa.Para solucionar este problema, mucha gente usará el comando find para encontrar cada archivo y pasarlos uno por uno al comando "rm" de esta manera:
Mi problema es que necesitaba eliminar 500,000 archivos y estaba tardando demasiado.
Me topé con una forma mucho más rápida de eliminar archivos: el comando "buscar" tiene un indicador "-delete" incorporado. Esto es lo que terminé usando:
Usando este método, estaba eliminando archivos a una velocidad de aproximadamente 2000 archivos / segundo, ¡mucho más rápido!
También puede mostrar los nombres de los archivos a medida que los elimina:
... o incluso mostrar cuántos archivos se eliminarán, y luego el tiempo que lleva eliminarlos:
fuente
sudo find . -type f -deleteeliminar alrededor de 485 mil archivos y funcionó para mí. Tomó unos 20 segundos.puedes probar esto:
EDITAR: el comentario de ThiefMaster me sugiere que no revele esa práctica peligrosa a los jedis de shell jóvenes, así que agregaré una versión más "más segura" (en aras de preservar las cosas cuando alguien tiene un archivo "-rf. ..Pdf")
Después de ejecutar lo anterior, simplemente abra el archivo /tmp/dummy.sh en su favorito. editor y verifique en cada línea los nombres de archivos peligrosos, coméntelos si los encuentra.
Luego copie el script dummy.sh en su directorio de trabajo y ejecútelo.
Todo esto por razones de seguridad.
fuente
-rf .. .pdf-rftiene prioridad sobre-i, por lo que su segunda versión no es mejor (sin inspección manual). Y es básicamente inútil para la eliminación masiva, debido a la solicitud de cada archivo.Podrías usar una matriz bash:
De esta forma, se borrará en lotes de 1000 archivos por paso.
fuente
puedes usar este elogio
fuente
El rm comando tiene una limitación de archivos que puede eliminar simultáneamente.
Una posibilidad es que pueda eliminarlos utilizando varias veces las bases del comando rm en sus patrones de archivo, como:
También puede eliminarlos mediante el comando de búsqueda :
fuente
rmno tiene dicho límite en la cantidad de archivos que procesará (aparte de esoargc, no puede ser mayor queINT_MAX). Es la limitación del núcleo en el tamaño máximo de toda la matriz de argumentos (es por eso que la longitud de los nombres de archivo es significativa).Si son nombres de archivo con espacios o caracteres especiales, use:
Esta oración busca todos los archivos en el directorio actual (-maxdepth 1) con la extensión pdf (-name '* .pdf') y luego elimina cada uno (-exec rm "{}").
La expresión {} reemplaza el nombre del archivo y "{}" establece el nombre del archivo como cadena, incluidos espacios o caracteres especiales.
fuente
-execes que no invocas un shell. Las citas aquí no hacen absolutamente nada útil. (Evitan cualquier expansión de comodines y la división de señal en la cadena en la concha donde se escribe este comando, pero la cadena{}no contiene ningún espacio en blanco o concha caracteres comodín.)Estaba enfrentando el mismo problema al copiar el directorio de origen del formulario al destino
el directorio fuente tenía archivos ~ 3 lakcs
i utilizado cp con la opción -r y ha funcionado para mí
cp -r abc / def /
copiará todos los archivos de abc a def sin avisar demasiado de la lista de argumentos
fuente
Pruebe esto también. Si desea eliminar archivos / carpetas superiores a 30/90 días (+) o inferiores a 30/90 (-) días, puede usar los siguientes comandos ex
Por ejemplo: para 90 días excluye lo anterior después de 90 días elimina archivos / carpetas, significa 91,92 .... 100 días
Por ejemplo: para los últimos archivos de 30 días que desea eliminar, utilice el siguiente comando (-)
Si quieres usar los archivos durante más de 2 días
Si desea ver los archivos / carpetas solo del último mes. Ex:
Por encima de 30 días más, solo enumere los archivos / carpetas Ej:
fuente
Me sorprende que no haya
ulimitrespuestas aquí. Cada vez que tengo este problema termino aquí o aquí . Entiendo que esta solución tiene limitaciones, peroulimit -s 65536parece que a menudo me sirve.fuente
Tuve el mismo problema con una carpeta llena de imágenes temporales que crecía día a día y este comando me ayudó a borrar la carpeta
La diferencia con los otros comandos es el parámetro mtime que tomará solo los archivos anteriores a X días (en el ejemplo 50 días)
Utilizando eso varias veces, disminuyendo en cada ejecución el rango de días, pude eliminar todos los archivos innecesarios
fuente
Solo sé una forma de evitar esto. La idea es exportar esa lista de archivos pdf que tiene a un archivo. Luego divide ese archivo en varias partes. Luego, elimine los archivos pdf enumerados en cada parte.
wc -l es contar cuántas líneas contiene la lista.txt. Cuando tenga la idea de cuánto tiempo es, puede decidir dividirlo por la mitad, hacia adelante o algo así. Uso del comando split -l Por ejemplo, divídalo en 600 líneas cada uno.
esto creará algunos archivos llamados xaa, xab, xac, etc., dependiendo de cómo lo divida. Ahora para "importar" cada lista de esos archivos en el comando rm, use esto:
Perdón por mi mal ingles.
fuente
pdf_format_sucks.docxeste también se eliminará ... ;-) Debe usar una expresión regular adecuada y precisa al buscar los archivos pdf.still_pdf_format_sucks.docxserá eliminado. El punto.en".pdf"la expresión regular coincide con cualquier carácter. Sugeriría en"[.]pdf$"lugar de.pdf.Me encontré con este problema varias veces. Muchas de las soluciones ejecutarán el
rmcomando para cada archivo individual que deba eliminarse. Esto es muy ineficiente:Terminé escribiendo un script de Python para eliminar los archivos basados en los primeros 4 caracteres del nombre del archivo:
Esto funcionó muy bien para mí. Pude borrar más de 2 millones de archivos temporales en una carpeta en aproximadamente 15 minutos. Comenté el alquitrán del pequeño código para que cualquier persona con un conocimiento mínimo o nulo de Python pueda manipular este código.
fuente
Y otro:
printfes un shell incorporado, y que yo sepa, siempre ha sido así. Ahora dado queprintfno es un comando de shell (sino un incorporado), no está sujeto a "argument list too long ..." error fatal.Por lo tanto, podemos usarlo de forma segura con patrones de globo de shell como
*.[Pp][Dd][Ff], luego, canalizamos su salida para eliminar elrmcomando ( ), a travésxargs, lo que asegura que se ajusta a suficientes nombres de archivo en la línea de comando para no fallar elrmcomando, que es un shell mando.El
\0enprintfsirve como un separador nulo para los nombres de archivo wich son luego procesadas porxargscomando, utilizando (-0) como separador, por lo quermno falla cuando hay espacios en blanco u otros caracteres especiales en los nombres de archivo.fuente
printfno se trata de un shell incorporado, estará sujeto a la misma limitación.Puede crear una carpeta temporal, mover todos los archivos y subcarpetas que desea mantener a la carpeta temporal, luego eliminar la carpeta anterior y cambiar el nombre de la carpeta temporal a la carpeta anterior. Pruebe este ejemplo hasta que esté seguro de hacerlo en vivo:
El
rm -r big_foldereliminará todos los archivos en elbig_folderno importa cuántos. Solo tienes que tener mucho cuidado, primero tienes todos los archivos / carpetas que deseas mantener, en este caso fuefile1.pdffuente
Para borrar todo
*.pdfen un directorio/path/to/dir_with_pdf_files/Eliminar archivos específicos mediante el
rsyncuso de comodines es probablemente la solución más rápida en caso de que tenga millones de archivos. Y se encargará del error que esté recibiendo.(Paso opcional): EJECUTAR EN SECO. Para verificar lo que se eliminará sin eliminar. ``
. . .
Haz clic en consejos y trucos de rsync para obtener más trucos de rsync
fuente
Descubrí que para listas extremadamente grandes de archivos (> 1e6), estas respuestas eran demasiado lentas. Aquí hay una solución que usa procesamiento paralelo en python. Lo sé, lo sé, esto no es Linux ... pero nada más aquí funcionó.
(Esto me ahorró horas)
fuente
Me he enfrentado a un problema similar cuando había millones de archivos de registro inútiles creados por una aplicación que llenaba todos los inodos. Recurrí a "localizar", puse todos los archivos "ubicados" en un archivo de texto y luego los eliminé uno por uno. Tomó un tiempo pero hizo el trabajo!
fuente
locatenuevo cuando aún tenía espacio en su disco.Una versión un poco más segura que usar xargs, también no recursiva:
ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; doneFiltrar nuestros directorios aquí es un poco innecesario ya que 'rm' no lo eliminará de todos modos, y se puede eliminar por simplicidad, pero ¿por qué ejecutar algo que definitivamente devolverá un error?
fuente
lses un antipatrón común que definitivamente debe evitarse, y agrega una serie de errores adicionales aquí. Elgrep | grepsimplemente no es muy elegante.findson buenas y bien documentadas aquí y en otros lugares. Consulte, por ejemplo, mywiki.wooledge.org para obtener más información sobre este tema y otros relacionados.Usar GNU parallel (
sudo apt install parallel) es súper fácilEjecuta los comandos multiproceso donde '{}' es el argumento pasado
P.ej
ls /tmp/myfiles* | parallel 'rm {}'fuente
lsdirectamente a otros comandos es un antipatrón peligroso; eso, y el hecho de que la expansión del comodín causará el mismo error al ejecutarlscomo se experimentó en elrmcomando original .parallelhace que algunas personas que prefieren evitar la complejidad se sientan incómodas: si miras debajo del capó, es bastante opaco. Vea el hilo de la lista de correo en lists.gnu.org/archive/html/bug-parallel/2015-05/msg00005.html entre Stephane (uno de los galgos de Unix y Linux StackExchange ) y Ole Tange (autor de Parallel).xargs -Ptambién se paraleliza, pero lo hace de una manera más simple y tonta con menos partes móviles, lo que hace que su comportamiento sea mucho más fácil de predecir y razonar.Para eliminar los primeros 100 archivos:
rm -rf 'ls | cabeza -100 '
fuente
La siguiente opción parece simple para este problema. Obtuve esta información de otro hilo pero me ayudó.
Simplemente ejecute el comando anterior y hará la tarea.
fuente