¿por qué for loop no genera el error "argumento demasiado largo"?

9

Descubrí que esto generaría el error "argumento demasiado largo":

ls *.*

Y esto no lo plantearía:

for file in *.*
do
    echo $file
done

¿Por qué?

lamwaiman1988
fuente
¿Usaste el mismo caparazón en ambos experimentos? ¿Quizás /bin/bashvs. /bin/sh(que quizás sea un enlace al guión)?
maxschlepzig
Sí, hice el experimento con 10000 archivos con nombre de archivo que son bastante largos. "ls *" falló y "for f in *" tuvo éxito.
lamwaiman1988

Respuestas:

13

El error de "argumento demasiado largo" es E2BIGprovocado por la execvellamada al sistema si el tamaño total de los argumentos (más el entorno, en algunos sistemas) es demasiado grande. La execvellamada es la que inicia procesos externos, específicamente cargando un archivo ejecutable diferente (hay una llamada diferente fork, para ejecutar un proceso separado cuyo código todavía es del mismo archivo ejecutable). El forbucle es una construcción de shell interna, por lo que no implica llamar execve. El comando ls *.*genera el error no cuando el globo se expande sino cuando lsse llama.

execvefalla con el error E2BIGcuando el tamaño total de los argumentos para el comando es mayor que el ARG_MAX límite . Puede ver el valor de este límite en su sistema con el comando getconf ARG_MAX. (Es posible que pueda superar este límite si tiene suficiente memoria; mantener bajo ARG_MAXgarantías que execvefuncionará siempre que no se produzca un error no relacionado).

Gilles 'SO- deja de ser malvado'
fuente
¿Y por qué Shell no tiene un límite?
lamwaiman1988
1
@ gunbuster363 El execvelímite es impuesto por el núcleo, pone límites porque los argumentos deben copiarse a través de la memoria del núcleo en un punto y no se puede permitir que los procesos del usuario soliciten una cantidad arbitraria de memoria de shell. Dentro del shell, no hay razón para tener ningún límite, todo lo que cabe en la memoria virtual está bien.
Gilles 'SO- deja de ser malvado'
5

Supongo que en el primer ejemplo lsse ejecuta a bashtravés de una llamada al sistema fork/ execpair, en el segundo, todo el trabajo es interno bash.

La execllamada tiene límites, el funcionamiento interno bashno tiene (o mejor, tiene límites diferentes que no tienen nada que ver exec, tal vez la cantidad de memoria disponible).

enzotib
fuente
Puede encontrar el límite execen /usr/include/linux/limits.husualmente, definido como ARG_MAX.
jw013
Si usamos el shell for loop, ¿crees que una gran lista de elementos consumirá toda la RAM?
lamwaiman1988
Esta respuesta es incorrecta. No es 'interno', es solo que los límites para argumentos y comandos son diferentes.
polinomio
5

Porque en el caso de lsesto es un argumento, y el número de argumentos es limitado.

En el caso del forciclo, es solo una lista de elementos. No hay límites (hasta donde yo sé) para eso.

Šimon Tóth
fuente
Definitivamente hay un límite para la expansión de shell. Está muy relacionado con la cantidad de RAM que tiene disponible. Pruebe esto; mi sistema de 4 GB de RAM explota en aproximadamente 15.2 millones de for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
argumentos de
44
@fred Realmente no pensé que mencionar RAM como límite sea necesario.
Šimon Tóth
2
Puede que no sea necesario, pero esa es la naturaleza de los comentarios ... alguien puede encontrarlo interesante o incluso valioso.
Peter.O
@fred: en realidad sí, si expandir argumentos muy grandes fuera un problema común, sería posible implementarlo sin tener todo en la memoria.
Matteo