Ligne de commande Bash et limite d'entrée

90

Y a-t-il une sorte de limite de caractères imposée dans bash (ou d'autres shells) pendant combien de temps une entrée peut durer? Si oui, quelle est cette limite de caractères?

Ie Est-il possible d'écrire une commande en bash qui est trop longue pour que la ligne de commande s'exécute? S'il n'y a pas de limite requise, y a-t-il une limite suggérée?

Derek Halden
la source
2
La limite d' entrée est très différente de la limite d' argument au niveau du système d'exploitation (notez que certaines choses autres que les arguments, telles que les variables d'environnement, s'appliquent également à celui-ci). La commande générée transmise au système d'exploitation peut avoir plus ou moins de caractères que la commande shell qui l'a générée.
Charles Duffy

Réponses:

125

La limite de longueur d'une ligne de commande n'est pas imposée par le shell, mais par le système d'exploitation. Cette limite est généralement de l'ordre de cent kilo-octets. POSIX indique cette limite ARG_MAXet sur les systèmes conformes POSIX, vous pouvez l'interroger avec

$ getconf ARG_MAX    # Get argument limit in bytes

Par exemple, sur Cygwin, il s'agit de 32000, et sur les différents BSD et systèmes Linux que j'utilise, il est compris entre 131072 et 2621440.

Si vous devez traiter une liste de fichiers dépassant cette limite, vous voudrez peut-être consulter l' xargsutilitaire, qui appelle un programme à plusieurs reprises avec un sous-ensemble d'arguments ne dépassant pas ARG_MAX.

Pour répondre à votre question spécifique, oui, il est possible d'essayer d'exécuter une commande avec une liste d'arguments trop longue. Le shell fera une erreur avec un message le long de "liste d'arguments trop longue".

Notez que l' entrée d'un programme (comme lu sur stdin ou tout autre descripteur de fichier) n'est pas limitée (uniquement par les ressources de programme disponibles). Donc, si votre script shell lit une chaîne dans une variable, vous n'êtes pas limité par ARG_MAX. La restriction ne s'applique pas non plus aux shell-builtins.

Jens
la source
Bonne réponse, mais j'aimerais une clarification. Si j'avais une construction cmd <<< "$LONG_VAR"et que la valeur LONG_VAR dépassait la limite, cela ferait-il exploser ma commande?
Krzysztof Jabłoński
1
@ KrzysztofJabłoński Peu probable, car le contenu de LONG_VARest transmis sur stdin - et cela se fait entièrement dans le shell; il n'est pas étendu comme argument à cmd, donc la limite ARG_MAX pour fork () / exec () n'entre pas en jeu. Il est facile d'essayer par vous-même: créez une variable dont le contenu dépasse ARG_MAX et exécutez votre commande.
Jens
2
Voici la clarification, pour l'enregistrement: pour un fichier m4a 8 méga - octets, je l' ai fait: blah="$(cat /home/schwager/Music/Recordings/20090420\ 131623.m4a)"; cat <<< $blah >/dev/null. Ne notez aucune erreur.
Mike S
3
Petite mise en garde. Les variables d'environnement comptent également. Page de manuel sysconf > Il est difficile d'utiliser ARG_MAX car il n'est pas spécifié> combien d'espace d'argument pour exec (3) est consommé par les> variables d'environnement de l'utilisateur.
Gerrit
3
@ user188737 J'ai l'impression que c'est une grosse mise en garde dans BUGS . Par exemple xargssur les limites macOS 10.12.6 combien il tente de mettre en un exec()à ARG_MAX - 4096. Ainsi, l'utilisation de scripts xargspeut fonctionner, jusqu'au jour où quelqu'un met trop de choses dans l'environnement. Courir dans ce maintenant (contourner ce problème avec :) xargs -s ???.
neuralmer
44

Ok, les habitants. J'ai donc accepté les limites de longueur de la ligne de commande comme évangile depuis un certain temps. Alors, que faire de ses hypothèses? Naturellement, vérifiez-les.

J'ai une machine Fedora 22 à ma disposition (c'est-à-dire Linux avec bash4). J'ai créé un répertoire contenant 500 000 inodes (fichiers) de 18 caractères chacun. La longueur de la ligne de commande est de 9 500 000 caractères. Créé ainsi:

seq 1 500000 | while read digit; do
    touch $(printf "abigfilename%06d\n" $digit);
done

Et nous notons:

$ getconf ARG_MAX
2097152

Notez cependant que je peux faire ceci:

$ echo * > /dev/null

Mais cela échoue:

$ /bin/echo * > /dev/null
bash: /bin/echo: Argument list too long

Je peux exécuter une boucle for:

$ for f in *; do :; done

qui est un autre shell intégré.

Lecture attentive de la documentation desARG_MAX états, longueur maximum d'argument des fonctions exec . Cela signifie: sans appel exec, il n'y a pas de ARG_MAXlimitation. Cela expliquerait donc pourquoi les fonctions internes du shell ne sont pas limitées par ARG_MAX.

Et en effet, je peux lsmon répertoire si ma liste d'arguments contient 109948 fichiers, soit environ 2 089 000 caractères (donner ou prendre). Une fois que j'ajoute un autre fichier de nom de fichier à 18 caractères, j'obtiens une erreur de liste d'arguments trop longue . Cela ARG_MAXfonctionne donc comme annoncé: l'exécution échoue avec plus de ARG_MAXcaractères sur la liste d'arguments - y compris, il faut le noter, les données d'environnement.

Mike S
la source
Hmm. Je n'avais pas lu la réponse existante pour impliquer que les builtins étaient soumis à la contrainte en question, mais je peux certainement voir comment quelqu'un pourrait.
Charles Duffy
6
Oui, je pense qu'il est difficile de se souvenir - en particulier pour les nouveaux afficianados de la ligne de commande - que la situation d'appeler une commande intégrée bash ou de fourcher / d'exécuter une commande est différente de manière non évidente. Je voulais que cela soit clair. Une question que je reçois invariablement lors d'un entretien d'embauche (en tant qu'administrateur système Linux) est: "J'ai donc un tas de fichiers dans un répertoire. Comment puis-je les parcourir tous en boucle ..." Le questionneur se dirige invariablement vers la ligne limite de longueur et veut une solution find / while ou xargs. Dans le futur, je vais dire, "ah diable - utilisez juste une boucle for. Il peut le gérer!" :-)
Mike S
@MikeS alors que vous pouvez faire une boucle for, si vous pouvez utiliser un combo find-xargs, vous bifurquerez beaucoup moins et serez plus rapide. ;-)
Lester Cheung
4
@LesterCheung for f in *; do echo $f; donene bifurquera pas du tout (tous intégrés). Donc je ne sais pas qu'un combo find-xargs sera plus rapide; il n'a pas été testé. En effet, je ne sais pas quel est le problème de l'OP. Peut find /path/to/directory- être ne lui sera - t - il pas utile car il renverra le chemin du fichier. Peut-être qu'il aime la simplicité d'une for f in *boucle. Quoi qu'il en soit, la conversation porte sur la limite d'entrée de ligne et non sur l'efficacité. Restons donc sur le sujet, qui concerne la longueur de la ligne de commande.
Mike S
FWIW, le problème, si je me souviens bien, était simplement d'essayer d'écrire un shell en C et de déterminer combien de temps je devrais autoriser les entrées.
Derek Halden
-3

Il y a une limite de tampon de quelque chose comme 1024. La lecture se bloquera simplement au milieu de la pâte ou de l'entrée. Pour résoudre ce problème, utilisez l'option -e.

http://linuxcommand.org/lc3_man_pages/readh.html

-e utilise Readline pour obtenir la ligne dans un shell interactif

Changez votre lecture en read -e et le blocage d'entrée de ligne ennuyeux disparaît.

Paul Kenjora
la source
1
Il ne s'agit pas de read: "Ie est-il possible d'écrire une commande dans bash qui est trop longue pour que la ligne de commande s'exécute?"
Chai T. Rex
@ ChaiT.Rex vous avez en quelque sorte raison, mais voici la chose: essayez d'exécuter Bash de manière interactive sans Readline, c'est bash --noediting-à- dire , et à la nouvelle invite, essayez d'exécuter la commande echo somereallylongword, où somereallylongword est plus long que 4090 caractères. Essayé sur Ubuntu 18.04, le mot a été tronqué, donc évidemment cela a quelque chose à voir avec Readline non activé.
Amir
@Amir Intéressant! Vous avez raison! J'ai tenté d'éditer la réponse, mais j'ai ensuite réalisé que l'option -e ne s'applique pas à bash dans ce contexte (dans bash, elle quitte le shell immédiatement en cas d'erreur). Et je ne sais pas pourquoi Paul a pivoté pour lire. Quoi qu'il en soit, il y a une limite de tampon entre 4-5000 caractères lorsque bash est démarré avec --noreadline. C'est un effet secondaire que je ne savais pas ou que je n'attendais pas.
Mike S