Combien de temps peut être une ligne de commande qui peut être passée à sh -c ''
? (en bash et en bourne Shell)
La limite est bien inférieure à celle du système d'exploitation (dans le cas de Linux moderne).
Par exemple:
$ /bin/true $(seq 1 100000)
$ /bin/sh -c "/bin/true $(seq 1 100000)"
bash: /bin/sh: Argument list too long
Et comment pourrais-je contourner ce problème?
Mise à jour
Je veux noter que getconf
ne peut pas aider ici (car ce n'est pas une limite système):
$ seq 1 100000 | wc -c
588895
$ getconf ARG_MAX
2097152
Mise à jour # 2
Maintenant, j'ai compris quel est le point ici. Ce n'est pas une limite Shell, c'est une limite système mais pour la longueur de chaque argument, pas pour l'arglist entière.
$ /bin/true $(seq 1 100000)
$ /bin/true "$(seq 1 100000)"
bash: /bin/true: Argument list too long
Merci, CodeGnome, pour l'explication.
Un seul argument doit être plus court que MAX_ARG_STRLEN.
Selon ce lien :
Et comme limite supplémentaire depuis 2.6.23, un argument ne doit pas être plus long que MAX_ARG_STRLEN (131072). Cela peut devenir pertinent si vous générez un appel long comme "sh -c 'généré avec des arguments longs'".
C'est exactement le "problème" identifié par l'OP. Alors que le nombre d'arguments autorisés peut être assez important (voir getconf ARG_MAX
), lorsque vous passez une commande entre guillemets à /bin/sh , le shell interprète la commande entre guillemets comme une seule chaîne. Dans l'exemple de l'OP, c'est cette chaîne unique qui dépasse la limite MAX_ARG_STRLEN, pas la longueur de la liste d'arguments développée.
Les limites d'argument sont spécifiques à l'implémentation. Cependant, cet article du Linux Journal suggère plusieurs façons de les contourner, notamment l'augmentation des limites du système. Cela peut ne pas être directement applicable au PO, mais cela est néanmoins utile dans le cas général.
Le problème du PO n'est pas vraiment un vrai problème. La question est d'imposer une contrainte arbitraire qui ne résout pas un problème du monde réel.
Vous pouvez contourner cela assez facilement en utilisant des boucles. Par exemple, avec Bash 4:
for i in {1..100000}; do /bin/sh -c "/bin/true $i"; done
fonctionne très bien. Ce sera certainement lent, car vous générez un processus à chaque passage dans la boucle, mais il contourne certainement la limite de ligne de commande que vous rencontrez.
Si une boucle ne résout pas votre problème, veuillez mettre à jour la question pour décrire le problème que vous essayez de résoudre en utilisant des listes d'arguments très longues. L'exploration de limites de longueur de ligne arbitraires est un exercice académique et non un sujet pour Stack Overflow.
Je ne reçois pas ce message d'erreur. Mon secret? Guillemets simples:
/bin/sh -c '/bin/true $(seq 1 100000)'
Si j'utilise des guillemets doubles, j'obtiens cette erreur avec chaque shell:
$ /bin/sh -c "/bin/true $(seq 1 100000)"
-bash: /bin/sh: Argument list too long
$ /bin/bash -c "/bin/true $(seq 1 100000)"
-bash: /bin/bash: Argument list too long
$ /bin/ksh -c "/bin/true $(seq 1 100000)"
-bash: /bin/ksh: Argument list too long
$ /bin/zsh -c "/bin/true $(seq 1 100000)"
-bash: /bin/zsh: Argument list too long
La liste d'arguments est développée dans le shell actuel lorsque des guillemets doubles sont utilisés comme en témoigne le fait que Bash est celui qui génère l'erreur "-bash: ..." quel que soit le shell utilisé pour exécuter la commande. Sur mon système, sh
est Dash, soit dit en passant.
Cela est vrai même pour les autres shells "Host":
$ dash
$ /bin/bash -c '/bin/true $(seq 1 100000)'
$ /bin/bash -c "/bin/true $(seq 1 100000)"
dash: /bin/bash: Argument list too long
Patient: Docteur, ça fait mal quand je fais ça. "
Docteur: Ne faites pas ça.
Diminuez 100 000 jusqu'à ce que vous n'obteniez plus l'erreur
/bin/sh -c "/bin/true $(seq 1 99999)"
/bin/sh -c "/bin/true $(seq 1 99998)"
etc.
Créez un fichier avec #!/bin/sh
comme première ligne, puis mettre le reste de votre commande sur les lignes suivantes? :)
Plus sérieusement, vous pouvez également lire les commandes de STDIN en utilisant le -s
, pour pouvoir générer votre longue ligne de commande et la diriger vers /bin/sh -s
sur mon os c'est la longueur max obtenue par dichotomie
/bin/sh -c "/bin/true $(Perl -e 'print"a"x131061')"
donc ça donne 131071
mais il n'y a aucune raison d'avoir une ligne aussi longue; si c'est dû à un grand nombre d'arguments, "$ @" peut être utilisé à la place; par exemple
/bin/sh -c 'command "$@"' -- arg1 arg2 .. argn