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é?
El error de "argumento demasiado largo" es E2BIG
provocado por la execve
llamada al sistema si el tamaño total de los argumentos (más el entorno, en algunos sistemas) es demasiado grande. La execve
llamada 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 for
bucle 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 ls
se llama.
execve
falla con el error E2BIG
cuando 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_MAX
garantías que execve
funcionará siempre que no se produzca un error no relacionado).
execve
lí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.
Supongo que en el primer ejemplo ls
se ejecuta a bash
través de una llamada al sistema fork
/ exec
pair, en el segundo, todo el trabajo es interno bash
.
La exec
llamada tiene límites, el funcionamiento interno bash
no tiene (o mejor, tiene límites diferentes que no tienen nada que ver exec
, tal vez la cantidad de memoria disponible).
exec
en /usr/include/linux/limits.h
usualmente, definido como ARG_MAX
.
Porque en el caso de ls
esto es un argumento, y el número de argumentos es limitado.
En el caso del for
ciclo, es solo una lista de elementos. No hay límites (hasta donde yo sé) para eso.
for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
/bin/bash
vs./bin/sh
(que quizás sea un enlace al guión)?