pourquoi la boucle ne déclenche pas l'erreur "argument trop long"?

9

J'ai trouvé que cela soulèverait l'erreur "argument trop long":

ls *.*

Et cela ne le soulèverait pas:

for file in *.*
do
    echo $file
done

Pourquoi?

lamwaiman1988
la source
Avez-vous utilisé le même shell dans les deux expériences? Peut-être /bin/bashvs /bin/sh(qui est peut-être un lien vers un tiret)?
maxschlepzig
Oui, j'ai fait l'expérience avec 10000 fichiers avec des noms de fichiers assez longs. "ls *" a échoué et "pour f dans *" a réussi.
lamwaiman1988

Réponses:

13

L'erreur «argument trop long» est déclenchée E2BIGpar l' execveappel système si la taille totale des arguments (plus l'environnement, sur certains systèmes) est trop grande. L' execveappel est celui qui démarre les processus externes, en particulier le chargement d'un fichier exécutable différent (il existe un appel différent fork, pour exécuter un processus distinct dont le code provient toujours du même fichier exécutable). La forboucle est une construction de shell interne, elle n'implique donc pas d'appel execve. La commande ls *.*déclenche l'erreur non pas lorsque le glob est développé mais quand lsest appelé.

execveéchoue avec l'erreur E2BIGlorsque la taille totale des arguments de la commande est supérieure à la ARG_MAX limite . Vous pouvez voir la valeur de cette limite sur votre système avec la commande getconf ARG_MAX. (Il est possible que vous puissiez dépasser cette limite si vous avez suffisamment de mémoire; garder sous des ARG_MAXgaranties qui execvefonctionneront tant qu'aucune erreur non liée ne se produit.)

Gilles 'SO- arrête d'être méchant'
la source
et pourquoi shell n'avait-il pas de limite?
lamwaiman1988
1
@ gunbuster363 La execvelimite est appliquée par le noyau, elle impose des limites car les arguments doivent être copiés via la mémoire du noyau à un moment donné et les processus utilisateur ne peuvent pas être autorisés à demander une quantité arbitraire de mémoire shell. À l'intérieur du shell, il n'y a aucune raison d'avoir une limite, tout ce qui tient dans la mémoire virtuelle est très bien.
Gilles 'SO- arrête d'être méchant'
5

Je suppose que dans le premier exemple lsest exécuté à partir d' bashun appel système fork/ execpair, dans le second, tout le travail est interne à bash.

L' execappel a des limites, le fonctionnement interne de bashn'a pas (ou mieux, a des limites différentes qui n'ont rien à voir avec exec, peut-être la quantité de mémoire disponible).

enzotib
la source
Vous pouvez trouver la limite à execen /usr/include/linux/limits.hgénéral, définie comme ARG_MAX.
jw013
Si nous utilisons le shell for loop, pensez-vous qu'une grande liste d'articles consommera toute la RAM?
lamwaiman1988
Cette réponse est incorrecte. Ce n'est pas «interne», c'est juste que les limites des arguments et des commandes sont différentes.
polynôme
5

Parce que dans le cas lsc'est un argument, et le nombre d'arguments est limité.

Dans le cas du forcycle, c'est juste une liste d'articles. Il n'y a pas de limites (à ma connaissance) à cela.

Šimon Tóth
la source
Il y a certainement une limite à l'expansion du shell. Cela dépend beaucoup de la quantité de RAM dont vous disposez. Essayez ceci; mon système de 4 Go de RAM souffle un joint à environ 15,2 millions d' for i in {00000001..20000000} ;do ((10#$i==1)) && break; done
arguments de
4
@fred Je ne pensais pas vraiment qu'il soit nécessaire de mentionner la RAM comme limite.
Šimon Tóth
2
Ce n'est peut-être pas nécessaire, mais c'est la nature des commentaires .. quelqu'un peut le trouver intéressant, ou même de valeur.
Peter.O
@fred: en fait oui, si l'expansion de très gros arguments était un problème courant, il serait possible de l'implémenter sans tout garder en mémoire.
Matteo