«Liste d'arguments trop longue»: comment y faire face sans modifier ma commande?

18

Lorsque j'exécute une commande comme ls */*/*/*/*.jpg, j'obtiens l'erreur

-bash: /bin/ls: Argument list too long

Je sais pourquoi cela se produit: c'est parce qu'il y a une limite de noyau sur la quantité d'espace pour les arguments d'une commande. Le conseil standard est de changer la commande que j'utilise, pour éviter d'exiger autant d'espace pour les arguments (par exemple, utiliser findet xargs).

Que faire si je ne souhaite pas modifier la commande? Et si je veux continuer à utiliser la même commande? Comment puis-je faire en sorte que les choses "fonctionnent simplement", sans obtenir cette erreur? Quelles solutions sont disponibles?

DW
la source
Lecture utile: Bash FAQ 95 . Sans changer votre commande, vous ne pouvez pas faire grand-chose à part recompiler pour augmenter la taille maximale de votre liste d'arguments, ou modifier la structure de votre répertoire pour qu'il y ait moins de fichiers.
jw013
1
@ jw013 basé sur la version du noyau linux, il peut être possible d'augmenter la liste des arguments - voir unix.stackexchange.com/a/45161/8979 pour plus de détails sur le changement dans les systèmes récents.
Ulrich Dangel
@UlrichDangel, Yup, c'est possible! Voir ma réponse; ma réponse montre comment le faire (sous Linux, avec un noyau assez récent).
DW

Réponses:

26

Sous Linux, la quantité maximale d'espace pour les arguments de commande est de 1 / 4e de la quantité d'espace de pile disponible. Ainsi, une solution consiste à augmenter la quantité d'espace disponible pour la pile.

Version courte: exécutez quelque chose comme

ulimit -s 65536

Version plus longue: la quantité d'espace disponible par défaut pour la pile est d'environ 8192 Ko. Vous pouvez voir la quantité d'espace disponible, comme suit:

$ ulimit -s
8192

Choisissez un plus grand nombre et définissez la quantité d'espace disponible pour la pile. Par exemple, si vous souhaitez autoriser jusqu'à 65 536 Ko pour la pile, exécutez ceci:

$ ulimit -s 65536

Vous devrez peut-être jouer avec sa taille, en utilisant des essais et erreurs. Dans de nombreux cas, cela est une solution rapide et sale qui éliminera la nécessité de modifier la commande et le travail sur la syntaxe find, xargsetc. (même si je me rends compte qu'il ya d' autres avantages à le faire).

Je pense que c'est spécifique à Linux. Je soupçonne que cela n'aidera probablement aucun autre système d'exploitation Unix (non testé).

DW
la source
1
Vous pouvez vérifier comme ça que cela a fonctionné: $ getconf ARG_MAX 2097152 $ ulimit -s 65535 $ getconf ARG_MAX 16776960
Alex
2

Cet article du Linux Journal propose 4 solutions. Seule la quatrième solution n'implique pas de modifier la commande:

La méthode n ° 4 consiste à augmenter manuellement le nombre de pages allouées dans le noyau pour les arguments de ligne de commande. Si vous regardez le fichier include / linux / binfmts.h, vous trouverez ce qui suit en haut:

/*
 * MAX_ARG_PAGES defines the number of pages allocated for   arguments
 * and envelope for the new program. 32 should suffice, this gives
 * a maximum env+arg of 128kB w/4KB pages!
 */
#define MAX_ARG_PAGES 32

Afin d'augmenter la quantité de mémoire dédiée aux arguments de ligne de commande, il vous suffit de fournir la valeur MAX_ARG_PAGES avec un nombre supérieur. Une fois cette modification enregistrée, recompilez, installez et redémarrez simplement le nouveau noyau comme vous le feriez normalement.

Sur mon propre système de test, j'ai réussi à résoudre tous mes problèmes en augmentant cette valeur à 64. Après des tests approfondis, je n'ai rencontré aucun problème depuis le changement. Cela est tout à fait attendu car même avec un MAX_ARG_PAGESréglage à 64, la ligne de commande la plus longue possible que je pourrais produire n'occuperait que 256 Ko de mémoire système - pas beaucoup selon les normes matérielles du système d'aujourd'hui.

Les avantages de la méthode n ° 4 sont évidents. Vous pouvez maintenant simplement exécuter la commande comme vous le feriez normalement, et elle se termine avec succès. Les inconvénients sont également évidents. Si vous augmentez la quantité de mémoire disponible sur la ligne de commande au-delà de la quantité de mémoire système disponible, vous pouvez créer une attaque DOS sur votre propre système et la faire planter. Sur les systèmes multi-utilisateurs en particulier, même une petite augmentation peut avoir un impact significatif car chaque utilisateur se voit alors allouer de la mémoire supplémentaire. Par conséquent, testez toujours en profondeur dans votre propre environnement, car c'est le moyen le plus sûr de déterminer si la méthode n ° 4 est une option viable pour vous.

Je reconnais que la limitation est très gênante.

Franck Dernoncourt
la source
1

Au lieu de ls */*/*/*/*.jpg, essayez:

echo */*/*/*/*.jpg | xargs ls

xargs(1) sait quel est le nombre maximal d'arguments sur le système et décomposera son entrée standard pour appeler la ligne de commande spécifiée plusieurs fois sans plus d'arguments que cette limite, quelle qu'elle soit (vous pouvez également la définir inférieure à le maximum du système d'exploitation en utilisant l' -noption).

Par exemple, supposons que la limite est de 3 arguments et que vous disposez de cinq fichiers. Dans ce cas xargs, s'exécutera lsdeux fois:

  1. ls 1.jpg 2.jpg 3.jpg
  2. ls 4.jpg 5.jpg

Souvent, cela convient parfaitement, mais pas toujours - par exemple, vous ne pouvez pas compter sur ls(1) pour trier correctement toutes les entrées, car chaque lsinvocation distincte ne triera que le sous-ensemble d'entrées qui lui est donné par xargs.

Bien que vous puissiez dépasser la limite comme suggéré par d'autres, il y aura toujours une limite - et un jour votre collection JPG la dépassera à nouveau. Vous devez préparer votre script (s) pour faire face à un nombre infini ...

Mikhail T.
la source
Merci pour l'idée! Ce n'est pas une mauvaise solution de contournement. Deux mises en garde: 1. Cela interrompt les répertoires et les noms de fichiers qui ont des espaces dans leur nom, donc ce n'est pas un substitut parfait. 2. Est-ce que ça va rencontrer le même problème avec Argument list too long, mais pour echoau lieu de ls, sur les shells où echon'est pas une commande intégrée au shell? (Peut-être que ce n'est pas un problème dans la plupart des obus, alors ce n'est peut-être pas pertinent.)
DW
1
Oui, les caractères spéciaux dans les noms de fichiers posent problème. Votre meilleur pari est d'utiliser findavec le -print0prédicat - et de canaliser sa sortie xargsavec l' -0option. echoest un shell intégré et ne souffre pas de la limitation en ligne de commande de exec(3).
Mikhail T.