usr too solve long lista larga expr demasiado argumentos argument arg linux unix command-line-arguments

linux - too - Error de la lista de argumentos demasiado larga para los comandos rm, cp, mv



solve argument list too long (30)

tl; dr

Es una limitación del núcleo en el tamaño del argumento de la línea de comandos. Utilice un bucle for lugar.

Origen del problema

Este es un problema del sistema, relacionado con execve y la constante ARG_MAX . Hay mucha documentación sobre eso (vea man execve , wiki de debian ).

Básicamente, la expansión produce un comando (con sus parámetros) que excede el límite ARG_MAX . En el kernel 2.6.23 , el límite se estableció en 128 kB . Esta constante se ha incrementado y puede obtener su valor ejecutando:

getconf ARG_MAX # 2097152 # on 3.5.0-40-generic

Solución: Usando for Loop

Use un bucle for como se recomienda en http://mywiki.wooledge.org/BashFAQ/095 y no hay límite, excepto el espacio de memoria / RAM:

for f in *.pdf; do rm "$f"; done

También es un enfoque portátil, ya que los glob tienen un comportamiento sólido y constante entre shells ( parte de la especificación POSIX ).

Nota: Como lo señalan varios comentarios, esto es de hecho 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 que solo una acción.

Solución: usando find

Si insiste, puede usar find pero realmente no usa xargs ya que "es peligroso (está roto, es explotable, etc.) cuando se lee una entrada no delimitada por NUL" :

find . -maxdepth 1 -name ''*.pdf'' -delete

El uso de -maxdepth 1 ... -delete lugar de -exec rm {} + permite find simplemente las llamadas requeridas del sistema sin usar un proceso externo, por lo tanto más rápido (gracias al comentario de @chepner ).

Referencias

Tengo varios cientos de archivos PDF bajo un directorio en UNIX. Los nombres de los PDF son realmente largos (aprox. 60 caracteres).

Cuando trato de eliminar todos los 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 también este error para los comandos mv y cp ? Si es así, ¿cómo resolver estos comandos?


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)

# delete files import os as os import glob import multiprocessing as mp directory = r''your/directory'' os.chdir(directory) files_names = [i for i in glob.glob(''*.{}''.format(''pdf''))] # report errors from pool def callback_error(result): print(''error'', result) # delete file using system command def delete_files(file_name): os.system(''rm -rf '' + file_name) pool = mp.Pool(12) # or use pool = mp.Pool(mp.cpu_count()) if __name__ == ''__main__'': for file_name in files_names: print(file_name) pool.apply_async(delete_files,[file_name], error_callback=callback_error)


El comando rm tiene una limitación de archivos que puede eliminar simultáneamente.

Una posibilidad puede eliminarlos utilizando varias veces las bases de comandos rm en sus patrones de archivo, como:

rm -f A*.pdf rm -f B*.pdf rm -f C*.pdf ... rm -f *.pdf

También puede eliminarlos a través del comando de búsqueda :

find . -name "*.pdf" -exec rm {} /;


He enfrentado 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", coloqué todos los archivos "localizados" d en un archivo de texto y luego los eliminé uno por uno. Tomó un tiempo pero hizo el trabajo!


Intente esto también. Si desea eliminar archivos / carpetas de más de 30/90 días (+) o de menos de 30/90 (-) días, puede usar los siguientes comandos ex

Por ejemplo: para 90 días excluye lo anterior, después de que 90 días se eliminen los archivos / carpetas, esto significa 91,92 ... 100 días

find <path> -type f -mtime +90 -exec rm -rf {} /;

Por ejemplo: solo para los últimos archivos de 30 días que desea eliminar, use el siguiente comando (-)

find <path> -type f -mtime -30 -exec rm -rf {} /;

Si quieres giz los archivos por más de 2 días

find <path> -type f -mtime +2 -exec gzip {} /;

Si quieres ver los archivos / carpetas solo de un mes pasado. Ex:

find <path> -type f -mtime -30 -exec ls -lrt {} /;

Por encima de 30 días solo más, luego enumere los archivos / carpetas Ex:

find <path> -type f -mtime +30 -exec ls -lrt {} /; find /opt/app/logs -type f -mtime +30 -exec ls -lrt {} /;


La razón por la que esto ocurre es porque bash realmente expande el asterisco a cada archivo coincidente, produciendo una línea de comandos muy larga.

Prueba esto:

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

Advertencia: esta es una búsqueda recursiva y también encontrará (y eliminará) los archivos en los subdirectorios. Agregue -f al comando rm solo si está seguro de que no quiere confirmación.

Puede hacer lo siguiente para hacer que el comando no recursivo:

find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm

Otra opción es usar la -delete de find:

find . -name "*.pdf" -delete


La siguiente opción parece simple para este problema. Obtuve esta información de algún otro hilo pero me ayudó.

for file in /usr/op/data/Software/temp/application/openpages-storage/*; do cp "$file" /opt/sw/op-storage/ done

Simplemente ejecute el comando anterior y hará la tarea.


Me encontré con este problema unas cuantas veces. Muchas de las soluciones ejecutarán el comando rm para cada archivo individual que deba eliminarse. Esto es muy ineficiente:

find . -name "*.pdf" -print0 | xargs -0 rm -rf

Terminé escribiendo un script en python para eliminar los archivos basados ​​en los primeros 4 caracteres en el nombre del archivo:

import os filedir = ''/tmp/'' #The directory you wish to run rm on filelist = (os.listdir(filedir)) #gets listing of all files in the specified dir newlist = [] #Makes a blank list named newlist for i in filelist: if str((i)[:4]) not in newlist: #This makes sure that the elements are unique for newlist newlist.append((i)[:4]) #This takes only the first 4 charcters of the folder/filename and appends it to newlist for i in newlist: if ''tmp'' in i: #If statment to look for tmp in the filename/dirname print (''Running command rm -rf ''+str(filedir)+str(i)+''* : File Count: ''+str(len(os.listdir(filedir)))) #Prints the command to be run and a total file count os.system(''rm -rf ''+str(filedir)+str(i)+''*'') #Actual shell command print (''DONE'')

Esto funcionó muy bien para mí. Pude eliminar más de 2 millones de archivos temporales en una carpeta en aproximadamente 15 minutos. Comenté el contenido del código para que cualquier persona con un conocimiento mínimo o nulo de Python pueda manipular este código.


Me enfrentaba al mismo problema al copiar el directorio de origen del formulario al destino

directorio de origen tenía archivos ~ 3 lakcs

Utilicé cp con la opción -r y funcionó para mí

cp -r abc / def /

copiará todos los archivos desde abc a def sin avisar de la lista de argumentos demasiado larga


Me sorprende que no haya respuestas ulimit aquí. Cada vez que tengo este problema termino here o here . Entiendo que esta solución tiene limitaciones, pero ulimit -s 65536 parece hacer el truco a menudo.


O puedes probar:

find . -name ''*.pdf'' -exec rm -f {} /;


Otra respuesta es forzar a xargs a procesar los comandos en lotes. Por ejemplo, para delete los archivos 100 a la vez, cd en el directorio y ejecute esto:

echo *.pdf | xargs -n 100 rm


Para eliminar los primeros 100 archivos:

rm -rf ''ls | cabeza -100 ''


Para eliminar todos los *.pdf en un directorio /path/to/dir_with_pdf_files/

mkdir empty_dir # Create temp empty dir rsync -avh --delete --include ''*.pdf'' empty_dir/ /path/to/dir_with_pdf_files/

Eliminar archivos específicos a través de rsync utilizando comodines es probablemente la solución más rápida en caso de que tenga millones de archivos. Y se hará cargo del error que está recibiendo.

(Paso opcional): DRY RUN. Para comprobar qué se eliminará sin eliminar. `

rsync -avhn --delete --include ''*.pdf'' empty_dir/ /path/to/dir_with_pdf_files/

. . .

Haz clic en los consejos y trucos de rsync para obtener más hacks rsync


Podrías usar una matriz bash:

files=(*.pdf) for((I=0;I<${#files[*]};I+=1000)); do rm -f ${files[@]:I:1000}; done

De esta manera se borrarán en lotes de 1000 archivos por paso.


Puede crear una carpeta temporal, mover todos los archivos y subcarpetas que desea mantener en la carpeta temporal, luego eliminar la carpeta antigua y cambiar el nombre de la carpeta temporal a la carpeta anterior. Pruebe este ejemplo hasta que esté seguro de hacerlo en vivo:

mkdir testit cd testit mkdir big_folder tmp_folder touch big_folder/file1.pdf touch big_folder/file2.pdf mv big_folder/file1,pdf tmp_folder/ rm -r big_folder mv tmp_folder big_folder

rm -r big_folder eliminará todos los archivos de big_folder sin importar cuántos. Solo tiene que ser muy cuidadoso, primero tiene todos los archivos / carpetas que desea conservar, en este caso era file1.pdf


Sólo sé una manera de evitar esto. La idea es exportar esa lista de archivos pdf que tiene en un archivo. Luego divide ese archivo en varias partes. A continuación, elimine los archivos pdf que figuran en cada parte.

ls | grep .pdf > list.txt wc -l list.txt

wc -l es contar cuántas líneas contiene list.txt. Cuando tenga la idea de cuánto tiempo es, puede decidir dividirlo por la mitad, hacia adelante o algo así. Usando el comando split -l Por ejemplo, divídalo en 600 líneas cada uno.

split -l 600 list.txt

esto creará unos cuantos archivos llamados xaa, xab, xac, etc., dependiendo de cómo se dividan. Ahora para "importar" cada lista en esos archivos en el comando rm, usa esto:

rm $(<xaa) rm $(<xab) rm $(<xac)

Perdón por mi mal ingles.


Si intenta eliminar una gran cantidad de archivos al mismo tiempo (eliminé un directorio con 485,000+ hoy), probablemente se encontrará con este error:

/bin/rm: Argument list too long.

El problema es que cuando escribe 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, muchas personas usarán el comando buscar para encontrar cada archivo y pasarlos uno por uno al comando "rm" de esta manera:

find . -type f -exec rm -v {} /;

Mi problema es que necesitaba eliminar 500,000 archivos y tardaba demasiado.

Me topé con una forma mucho más rápida de eliminar archivos: ¡el comando "buscar" tiene una marca de "-eliminar" incorporada! Esto es lo que terminé usando:

find . -type f -delete

Con este método, estaba eliminando archivos a una velocidad de aproximadamente 2000 archivos / segundo, ¡mucho más rápido!

También puedes mostrar los nombres de archivo a medida que los elimines:

find . -type f -print -delete

... o incluso mostrar cuántos archivos se eliminarán, luego el tiempo que demora en eliminarlos:

root@devel# ls -1 | wc -l && time find . -type f -delete 100000 real 0m3.660s user 0m0.036s sys 0m0.552s


Si necesita mantener un servidor o sistema receptivo mientras elimina una gran cantidad de archivos, la sleep entre cada instrucción de eliminación puede ser un buen método.

find . -name "*.pdf" -print0 | while read -d $''/0'' file do rm "$file" sleep 0.005 # Sleeps for 5ms, tweak as needed done


Si son nombres de archivo con espacios o caracteres especiales, use:

find -maxdepth 1 -name ''*.pdf'' -exec rm "{}" /;

Esta oración busca todos los archivos en el directorio actual (-maxdepth 1) con extensión pdf (-name ''* .pdf''), y luego, elimine cada uno (-exec rm "{}").

La expresión {} reemplaza el nombre del archivo y, "{}" establece el nombre del archivo como una cadena, incluidos espacios o caracteres especiales.


Si tiene problemas similares con grep , la solución más sencilla es retroceder un directorio y hacer una búsqueda recursiva.

Así que en lugar de

grep "something" *

puedes usar:

cd .. grep "something" -R search_in_this_dir/

Tenga en cuenta que también buscará de forma recursiva las subcarpetas del directorio "search_in_this_dir_dir".


Supongamos que el nombre del directorio de entrada es entrada y el nombre del directorio de salida es la salida. A continuación, puede utilizar bucle simple para copiar todos

for f in input/* do cp $f output done


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.

find . -name "*.png" -mtime +50 -exec rm {} /;

La diferencia con los otros comandos es el parámetro mtime que solo tomará los archivos más antiguos que X días (en el ejemplo 50 días)

Usando eso varias veces, disminuyendo en cada ejecución el rango de días, pude eliminar todos los archivos innecesarios


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 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 puede eliminarse por simplicidad, pero ¿por qué ejecutar algo que definitivamente devolverá un error?


Usar GNU en paralelo ( sudo apt install parallel ) es súper fácil

Ejecuta los comandos multiproceso donde ''{}'' es el argumento pasado

P.ej

ls /tmp/myfiles* | parallel ''rm {}''


Y otro:

cd /path/to/pdf printf "%s/0" *.[Pp][Dd][Ff] | xargs -0 rm

printf es un shell incorporado, y por lo que sé, siempre ha sido así. Ahora, dado que printf no es un comando de shell (sino un componente), no está sujeto a "error de la argument list too long ... ".

Por lo tanto, podemos usarlo de forma segura con patrones de shell shell, como *.[Pp][Dd][Ff] , luego canalizamos su salida para eliminar ( rm ) el comando, a través de xargs , lo que garantiza que se ajuste a suficientes nombres de archivo en el comando línea para no fallar el comando rm , que es un comando de shell.

El /0 en printf sirve como separador nulo para los nombres de archivo que luego son procesados ​​por el comando xargs , usándolo ( -0 ) como separador, por lo que rm no falla cuando hay espacios en blanco u otros caracteres especiales en los nombres de archivo .


puedes probar esto

for f in *.pdf do rm $f done

EDIT: El comentario de ThiefMaster me sugiere no divulgar una práctica tan peligrosa a los jóvenes jedis de shell, así que agregaré una versión más "segura" (para preservar las cosas cuando alguien tiene un archivo "-rf ... ..pdf")

echo "# Whooooo" > /tmp/dummy.sh for f in ''*.pdf'' do echo "rm -i $f" >> /tmp/dummy.sh done

Después de ejecutar lo anterior, simplemente abra el archivo /tmp/dummy.sh en su favorito. edite y revise cada línea en busca de nombres de archivo peligrosos, comentándolos si se encuentran.

Luego copie el script dummy.sh en su directorio de trabajo y ejecútelo.

Todo esto por razones de seguridad.


puedes usar este elogio

find -name "*.pdf" -delete


find . -type f -name ''*xxx'' -print -delete


find tiene una acción -delete :

find . -maxdepth 1 -name ''*.pdf'' -delete