Contexte de la question: selon spécifications POSIX , ARG_MAX est la longueur maximale des arguments de ligne de commande à exec()
famille de fonctions. Ce qui m'amène à croire que c'est le nombre réel d'arguments, mais cela n'a clairement pas fonctionné:
$ ulimit -s
8192
$ touch {1..18000}.jpg
$ rm *.jpg
$
De toute évidence, cela fonctionne bien, bien qu'il soit plus de 8192 articles. Selon réponse de D.W. , le 8192
est censé avoir une taille en Ko. Il est donc clair que l'hypothèse précédente était fausse.
C'est là que la vraie question entre en jeu: comment puis-je déterminer la quantité d'articles qui atteindront au-dessus de la limite de 8192 Ko? En d'autres termes, quel type de calcul je dois effectuer pour m'assurer que *.jpg
le type de glob se traduira par Argument list too long
Erreur ?
Veuillez noter qu'il ne s'agit pas d'un doublon de ce qui définit la taille maximale d'un seul argument de commande . Je connais getconf ARG_MAX
et ulimit -s
valeurs, ce n'est pas ma question. J'ai besoin de savoir comment générer suffisamment d'arguments de taille qui seront au-dessus de la limite . En d'autres termes, je dois trouver un moyen d'obtenir l'erreur, pas l'éviter.
En utilisant getconf ARG_MAX
pour générer une longue liste de x
et appeler un utilitaire externe avec cela comme argument générerait une erreur "Argument list too long":
$ /bin/echo $( Perl -e 'print "x" x $ARGV[0]' "$(getconf ARG_MAX)" )
/bin/sh: /bin/echo: Argument list too long
L'environnement et la longueur de la chaîne /bin/echo
sera inclus dans ce qui fait que l'erreur se produit, donc nous pouvons essayer de trouver le plus grand nombre possible en soustrayant ces derniers:
$ env
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin
(J'ai commencé ce Shell avec env -i sh
, donc il n'y a que la variable PATH
dans l'environnement)
$ /bin/echo $( Perl -e 'print "x" x ($ARGV[0] - length($ENV{"PATH"}) - length("/bin/echo"))' "$(getconf ARG_MAX)" )
sh: /bin/echo: Argument list too long
Encore trop longtemps. De combien?
i=0
while ! /bin/echo $( Perl -e 'print "x" x ($ARGV[0] - length($ENV{"PATH"}) - length("/bin/echo") - $ARGV[1])' "$(getconf ARG_MAX)" "$i" )
do
i=$(( i + 1 ))
done
Cette boucle se termine pour i=8
.
Il y a donc quatre octets que je ne peux pas immédiatement expliquer (quatre des huit doivent être pour la nom de la variable d'environnement PATH
). Ce sont les terminateurs nuls pour les quatre chaînes PATH
, la valeur de PATH
, /bin/echo
et la longue chaîne de caractères x
.
Notez que chaque argument se termine par null, donc plus vous avez d'arguments à la commande, plus leur longueur combinée peut être courte.
Aussi, juste pour montrer l'effet d'un grand environnement:
$ export BIG=$( Perl -e 'print "x" x $ARGV[0]' "$( getconf ARG_MAX )" )
$ /bin/echo hello
sh: /bin/echo: Argument list too long
$ /bin/echo
sh: /bin/echo: Argument list too long
Sur de nombreuses distributions Linux, vous pouvez découvrir quelle est la valeur actuelle de ARG_MAX en exécutant
getconf ARG_MAX
Un moyen simple de générer le message "Liste d'arguments trop longue" consiste à fournir une longue liste d'arguments; par exemple, sur mon système
/bin/echo "$(find / -xdev 2> /dev/null)"
fonctionne, mais
/bin/echo "$(find / -xdev 2> /dev/null)" "$(find / -xdev 2> /dev/null)"
produit
bash: /bin/echo: Argument list too long
Pour une discussion approfondie, voir " Liste d'arguments erreur trop longue pour les commandes rm, cp, mv " sur Stack Overflow.
P.S. La longueur en question est la quantité réelle de mémoire nécessaire pour stocker les arguments et l'environnement. Il n'est pas lié au nombre d'arguments.
Au lieu de répertorier tous les fichiers du système, ce qui prend une éternité et ne fonctionne pas sur des systèmes clairsemés, la commande
/bin/echo {1..200000}
est un moyen beaucoup plus rapide (163 ms) de générer l'erreur. Pour moi ARG_MAX
est 2097152
(2 097 152 de l'ordre de 2 millions) mais la commande contient toujours des erreurs.
Si votre Shell n'a pas {start..end}
, vous pouvez utiliser un peu plus lent (mais toujours plus rapide que de lister les fichiers)
/bin/echo $(seq 1 200000)
Si l'une des commandes ne fonctionne pas, augmentez simplement la valeur de fin jusqu'à ce qu'elle le fasse, jusqu'à ce que bash
manque de mémoire ou jusqu'à ce que seq
ne puisse pas compter plus.
Pour faciliter le démarrage d'un nouveau shell (exit
une fois terminé) et définir la limite sur une valeur inférieure (100 Ko):
$ bash
$ ulimit -s 100
Avec l'exemple que vous avez utilisé, l'erreur pourrait être déclenchée:
$ touch {1..100000}.jpg
bash: /usr/bin/touch: Argument list too long
Mais il vaut mieux utiliser quelque chose comme echo
. Comprenez qu'un module intégré peut ne pas déclencher une erreur, cette commande devrait fonctionner correctement:
$ echo {000001..100000}6789
Notez également que la quantité d'octets dépasse largement la limite définie ci-dessus (1,1 Mo):
$ echo {000001..100000}6789 | wc -c
1100000
Mais cette commande ne fonctionnera pas:
$ /bin/echo {000001..100000}6789
bash: /bin/echo: Argument list too long
La limite est définie par la taille de la liste d'arguments en octets ajoutée à la taille de l'environnement du Shell.