por que o loop for não gera o erro "argumento muito longo"?

9

Descobri que isso geraria o erro "argumento muito longo":

ls *.*

E isso não aumentaria:

for file in *.*
do
    echo $file
done

Por quê?

lamwaiman1988
fonte
Você usou o mesmo shell nos dois experimentos? Talvez /bin/bashvs. /bin/sh(que talvez seja um link para o dash)?
maxschlepzig
Sim, fiz o experimento com 10000 arquivos com nome de arquivo bastante longos. "ls *" falhou e "for f in *" foi bem-sucedido.
lamwaiman1988

Respostas:

13

O erro "argumento muito longo" é E2BIGgerado pela execvechamada do sistema se o tamanho total dos argumentos (mais o ambiente, em alguns sistemas) for muito grande. A execvechamada é aquela que inicia processos externos, carregando especificamente um arquivo executável diferente (há uma chamada diferente fork, para executar um processo separado cujo código ainda é do mesmo arquivo executável). O forloop é uma construção de shell interna, portanto, não envolve chamadas execve. O comando ls *.*gera o erro não quando o glob é expandido, mas quando lsé chamado.

execvefalha com o erro E2BIGquando o tamanho total dos argumentos para o comando é maior que o ARG_MAX limite . Você pode ver o valor desse limite em seu sistema com o comando getconf ARG_MAX. (É possível que você ultrapasse esse limite se tiver memória suficiente; mantendo as ARG_MAXgarantias de que execvefuncionará enquanto não ocorrer nenhum erro não relacionado.)

Gilles 'SO- parar de ser mau'
fonte
e por que a shell não tinha limite?
precisa saber é o seguinte
11
@ gunbuster363 O execvelimite é imposto pelo kernel, coloca limites porque os argumentos precisam ser copiados via memória do kernel em um ponto e os processos do usuário não podem solicitar uma quantidade arbitrária de memória shell. Dentro do shell, não há razão para ter qualquer limite, tudo o que se encaixa na memória virtual é bom.
Gilles 'SO- stop be evil'
5

Suponho que no primeiro exemplo lsseja executado bashatravés de uma chamada de sistema fork/ execpair, no segundo, todo o trabalho seja interno bash.

A execchamada tem limites, o trabalho interno em bashvez disso não tem (ou melhor, possui limites diferentes que não têm nada a ver com exec, talvez a quantidade de memória disponível).

enzotib
fonte
Você pode encontrar o limite para execem /usr/include/linux/limits.hgeral, definido como ARG_MAX.
jw013
Se usarmos o shell for loop, você acha que uma grande lista de itens consumirá toda a RAM?
precisa saber é o seguinte
Esta resposta está incorreta. Não é 'interno', é apenas que os limites para argumentos e comandos são diferentes.
polinômio
5

Porque, no caso ls, é um argumento, e o número de argumentos é limitado.

No caso do forciclo, é apenas uma lista de itens. Não há limites (até onde eu saiba) para isso.

Šimon Tóth
fonte
Definitivamente, há um limite para a expansão do shell. Está muito relacionado à quantidade de RAM que você tem disponível. Tente isso; meu sistema RAM 4GB sopra uma junta em cerca de 15,2 milhões de args de 8 bytes:for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
Peter.O
4
@ Fred Eu realmente não acho necessário mencionar a RAM como limite.
Šimon Tóth
2
Pode não ser necessário, mas essa é a natureza dos comentários. Alguém pode achar interessante, ou mesmo de valor.
precisa saber é o seguinte
@ Fred: na verdade, sim, se expandir argumentos muito grandes fosse um problema comum, seria possível implementá-lo sem manter tudo na memória.
Matteo