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 mv
y cp
comandos 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
-f
comando 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
-delete
bandera de find :fuente
xargs
divide específicamente la lista y emite varios comandos si es necesario.-maxdepth 1
debe ser el primer argumento después del camino.-delete
bandera para eliminar los archivos que encuentra, e incluso si no fuera así, se consideraría una mejor práctica usar-exec
para ejecutar rm, en lugar de invocar xargs (que ahora son 3 procesos y una tubería en lugar de un solo proceso con-delete
o 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
.-exec
llamadarm
, 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 procesosxargs
que 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-delete
deberí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
for
bucle en su lugar.Origen del problema
Este es un problema del sistema, relacionado
execve
yARG_MAX
constante. 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_MAX
lí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
for
LoopUse un
for
bucle 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
find
Si insiste, puede usar
find
pero realmente no usar xargs ya que "es peligroso (roto, explotable, etc.) al leer entradas no delimitadas por NUL" :Usar en
-maxdepth 1 ... -delete
lugar de-exec rm {} +
permitefind
simplemente 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
for
bucle. Lo he usadofind
antes, pero siempre estoy buscando cómo hacerlo, ya que olvido las opciones, etc. todo el tiempo.for
parece más fácil de recordar en mi humilde opiniónfor f in *; do rm "$f"; done
find -exec
solución parece ser MUCHO más rápida que elfor
ciclo.4.15.0-1019-gcp
para 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.find
tiene una-delete
acción:fuente
xargs
, según la respuesta de Dennis, funciona según lo previsto.-exec
es eliminar un montón de archivos.-exec rm {} +
haría lo mismo, pero aún requiere iniciar al menos un proceso externo.-delete
permitefind
ejecutar simplemente el sistema requerido se llama a sí mismo sin usar un contenedor externo.Otra respuesta es forzar
xargs
procesamiento de los comandos en lotes. Por ejemplo adelete
los archivos100
a la vez,cd
en el directorio y ejecute esto:echo *.pdf | xargs -n 100 rm
fuente
echo
hay 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 -delete
eliminar 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
-rf
tiene 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
rm
no 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
-exec
es 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
ulimit
respuestas aquí. Cada vez que tengo este problema termino aquí o aquí . Entiendo que esta solución tiene limitaciones, peroulimit -s 65536
parece 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.docx
este también se eliminará ... ;-) Debe usar una expresión regular adecuada y precisa al buscar los archivos pdf.still_pdf_format_sucks.docx
será 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
rm
comando 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:
printf
es un shell incorporado, y que yo sepa, siempre ha sido así. Ahora dado queprintf
no 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 elrm
comando ( ), a travésxargs
, lo que asegura que se ajusta a suficientes nombres de archivo en la línea de comando para no fallar elrm
comando, que es un shell mando.El
\0
enprintf
sirve como un separador nulo para los nombres de archivo wich son luego procesadas porxargs
comando, utilizando (-0
) como separador, por lo querm
no falla cuando hay espacios en blanco u otros caracteres especiales en los nombres de archivo.fuente
printf
no 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_folder
eliminará todos los archivos en elbig_folder
no importa cuántos. Solo tienes que tener mucho cuidado, primero tienes todos los archivos / carpetas que deseas mantener, en este caso fuefile1.pdf
fuente
Para borrar todo
*.pdf
en un directorio/path/to/dir_with_pdf_files/
Eliminar archivos específicos mediante el
rsync
uso 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
locate
nuevo 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"; done
Filtrar 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
ls
es un antipatrón común que definitivamente debe evitarse, y agrega una serie de errores adicionales aquí. Elgrep | grep
simplemente no es muy elegante.find
son 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
ls
directamente 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 ejecutarls
como se experimentó en elrm
comando original .parallel
hace 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 -P
tambié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