NightAngel

Flux RSS 2.0

Argument list too long : Au delà des limitations et des arguments

http://www.sexycoolwink.com/photo/10105/Sexy-babes-resting-at-beach.html

Aujourd’hui, enfin hier (en fait on sait pas vraiment) j’ai procédé à la migration du forum Motorsport-Passion.com, les fichiers, la base de données, touSSa touSSa. Outre un important problème d’encodage (caractères non-latin mal convertis), à un moment j’ai du déplacer plusieurs milliers de fichiers d’un répertoire à un autre sous FreeBSD 7.0 et là j’ai rencontré une erreur un peu cocasse : “/bin/mv: Argument list too long” :shock: Par défaut il n’est donc pas possible de déplacer un si grand nombre de fichiers en utilisant la commande mv de FreeBSD. Détaillons 4 méthodes alternatives permettant de contourner ce problème…

À un moment donné au cours de votre carrière comme un utilisateur de Linux/Unix, vous êtes arrivés à tomber sur l’erreur suivante :

[user@localhost directory]$ mv * ../directory2
bash: /bin/mv: Argument list too long

L’erreur “Argument list too long” se produit quand un l’utilisateur met de nombreux arguments à une même commande, l’utilisateur doit se débrouiller par soi-même, puisque toutes les commandes système régulières (* ls, cp *, * rm, etc ..) sont soumises aux mêmes limitations. Cet article se concentrera sur quatre solutions différentes qui permettront de contourner ce problème, chaque méthode possède différents degrés de complexité et permet résoudre différents problèmes potentiels. Les solutions sont présentées ci-dessous par ordre de simplicité, suivant la logique du principe de fonctionnement du Rasoir d’Occam : si vous avez deux solutions équivalentes à un problème, choisissez la plus simple.

Méthode #1 : Scinder manuellement les arguments de la ligne de commande en petites grappes.

Exemple N°1

[user@localhost directory]$ mv [a-l]* ../directory2
[user@localhost directory]$ mv [m-z]* ../directory2

Cette méthode est la plus simple des quatre: il suffit de réutiliser la commande d’origine mais avec des arguments en moins, dans l’espoir que cela permette de résoudre le problème. Bien que cette méthode apporte une solution rapide, elle est loin d’être idéale. Cette méthode fonctionne bien si vous avez une liste de fichiers dont les noms sont répartis à travers l’alphabet. Cela vous permet de créer des divisions cohérentes, ce qui rend la tâche un peu plus aisée. Toutefois, cette méthode est un mauvais choix pour la manipulation de très grandes quantités de fichiers, car il s’agit de renvoyer de nombreuses commandes et une bonne partie de devinettes s’annonce.

Méthode #2 : Utiliser la commande “find”.

Exemple N°2

[user@localhost directory]$ find $directory -type f -name ‘*’ -exec mv
{} $directory2/. \;

La méthode n°2 consiste à filtrer la liste des fichiers par le biais de la commande find, puis de donner des instructions à chaque fichier basées sur un ensemble de paramètres déterminés dans la ligne de commande. En raison de l’intégration et de la flexibilité de la commande find, cette solution est facile à utiliser, très réussie et populaire. Elle vous permet de faire un travail sélectif à partir de sous-ensembles de fichiers en fonction de leurs nom, de leur la date de création, des autorisations, etc… Qui plus est, et c’est peut-être même le plus important, vous pouvez faire ça en une seule commande.

Le principal inconvénient de cette méthode est le temps nécessaire pour achever le processus. Contrairement à la méthode n°1, où des groupes de fichiers sont traités comme une unité, cette procédure inspecte les propriétés individuelles de chaque fichier avant d’effectuer l’opération demandée.

Méthode #3 : Créer une fonction. *

Exemple 3a

function large_mv ()
{ while read line1; do
mv directory/$line1 ../directory2
done
}
ls -1 directory/ | large_mv

Bien que la rédaction d’une fonction shell implique un certain niveau de complexité, je trouve que cette méthode permet un plus grand degré de flexibilité et de contrôle par rapport aux méthode n°1 et n°2 sus-citées.

Le courte fonction indiquée dans l’exemple 3a imite simplement la fonctionnalité de la commande find indiquée dans l’exemple n°2 : elle traite de chaque fichier individuellement. Cependant, en écrivant une fonction, il est possible d’effectuer un nombre d’actions illimité par fichier en utilisant toujours une seule commande :

Exemple 3b

function larger_mv ()
{ while read line1; do
md5sum directory/$line1 >> ~/md5sums
ls -l directory/$line1 >> ~/backup_list
mv directory/$line1 ../directory2
done
}
ls -1 directory/ | larger_mv

L’exemple 3b montre comment vous pouvez obtenir facilement un md5sum et une liste de sauvegarde de chaque fichier avant de les déplacer.

Malheureusement cette méthode exige également que chaque dossier soit traité individuellement, le temps de traitement est donc similaire à la méthode #2. Par expérience j’ai constaté que la méthode n°2 est un peu plus rapide que la fonction indiquée dans l’exemple 3a, la méthode #3 devrait être utilisée que dans les cas où la fonctionnalité supplémentaire est nécessaire.

Méthode #4: Recompiler le noyau Linux. **

Cette dernière méthode nécessite une mise en garde, car elle est de loin la solution la plus agressive. Cette méthode est présentée ici dans un souci de rigueur car, même si elle est valable, elle ne fait que déplacer le problème. Toutefois, s’il vous plaît prenez note qu’en raison de la nature avancée de la solution, seuls des utilisateurs expérimentés de Linux/Unix doivent tenter cette modification. En outre, assurez-vous de bien tester le résultat final dans votre environnement avant sa mise en oeuvre de façon permanente.

L’un des avantages d’utiliser un noyau open-source est de pouvoir examiner exactement de quelle manière il est configuré et de pouvoir modifier ses paramètres en fonction des besoins individuels de votre système. La méthode n°4 implique d’augmenter manuellement le nombre de pages qui sont allouées par le noyau aux arguments de la ligne de commande. Il faut éditer le fichier include/linux/binfmts.h et (vers le haut) vous trouverez :

/*
* 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 la ligne de commande, il vous suffit d’augmenter la valeur de MAX_ARG_PAGES. Une fois cette modification enregistrée, il suffit de recompiler, d’installer et de redémarrer avec 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 de nombreux essais, je n’ai pas connu un seul problème depuis le changement.

Les avantages de la méthode #4 sont clairs. Vous êtes maintenant en mesure de lancer simplement la commande, comme vous le feriez normalement, et tout se passe bien. Les inconvénients sont clairs eux aussi. Si vous allouez à la ligne de commande une quantité de mémoire supérieure à la quantité de mémoire système disponible, vous pouvez créer une attaque DOS sur votre propre système et de provoquer un crash de ce dernier. Sur les systèmes multi-utilisateurs en particulier, même une légère augmentation peut avoir un impact significatif car la mémoire supplémentaire est attribuée à chaque utilisateur. Une longue et intensive période de tests dans votre propre environnement reste le moyen le plus sûr pour déterminer si la méthode n°4 est une option viable.

Conclusion

Bien que lors de la rédaction de cet article, je suis tombé sur de nombreuses explications pour l’erreur “liste d’arguments trop long”. Etant donné que le message commence par “bash:”, de nombreuses personnes ont blâmé le shell bash. De la même manière, en voyant le nom de l’application dans l’erreur, des personnes ont mis en cause cette dernière. Au lieu de cela, comme j’espère l’avoir démontré dans la méthode #4, le noyau est lui-même “responsable” de cette limitation. En dépit de l’enthousiasme de l’auteur de binfmts.h, beaucoup d’entre nous ont trouvé que 128 Ko de mémoire dédiée pour la ligne de commande n’est tout simplement pas assez. Il faut espérer que, en utilisant une des méthodes ci-dessus, nous pouvons tous oublier celle-ci et se remettre au travail.

Notes

* Toutes les fonctions ont été écrites sur un shell bash.

** La solution présentée dans la méthode #4 a été trouvée lors d’un débat dans la mailing liste linux-kernel en Mars 2000. Voir le sujet “Argument List too Long” dans les archives pour avoir la discussion en entier.


Article principalement inspiré du billet “Argument list too long”: Beyond Arguments and Limitations rédigé par Alessandre S. Naro sur linuxjournal.com le Jeudi 9 Mai 2002.


Après un moment de détente imposé par le présent billet, piratons un compte Gmail…

.

Facebook, t'aimes ça hein !

12 commentaires

  1. avatar

    J’ai du arrêter la lecture a FreeBSD, j’ai trop rigolé

  2. avatar

    t’as bien de la chance , moi je post en pure amitié , car j’ai rien compris :razz:

  3. avatar

    Lol, j’ai compris deux trois choses, mais pas tout. Enfin c’est de la programmation quoi ^^
    Sinon la petite vidéo est bien sympa… merci beaucoup mon ami.
    Beau billet mais il passe tout seul ;)

  4. avatar

    Donc… si j’ai bien compris, au final, les commandes précédant la recompilation du noyau sont utiles mais…pas suffisantes?

    Toi tu as augmenté la valeur de ton noyau Linux parce qu’avant celui-ci n’offrait pas la possibilité de traiter et de migrer beaucoup de dossiers divers et variés en même temps?
    La valeur allouée 64 aurait-elle un rapport avec des bits? megabits? gigabits? (j’essaie en même temps de comprendre un peu votre boulot à vous les informaticiens, je suis curieuse :) )

    C’est déjà super bien de savoir qu’une ligne de commande c’est dans démarrer/exécuter! Seulement toi je pense que tu dois avoir d’autres combines pour y accéder non? :razz:

    Ah oui aussi, tu as fais une faute d’orthographe dans la partie Méthode#1 sous l’exemple.
    “[...] il suffit de réutilisé [...]”
    Voilà j’espère avoir des réponses à mes petits questions! Ca prouve que je m’intéresse un minimum et que je ne suis pas là juste pour participer aux trollages et autres conneries diverses ^^!

    Bisousssss Paul (au fait j’ai essayé de changer mon avatar, il ne veut pas, faudra que tu m’explique…en plus celui que je voulais tester il était plus petit que la taille requise.)

    Voilou… :ooo

  5. avatar

    Youpi moi aussi j’ai fais une faute!

    —> “petitEs questions”

    re-Bisous!

  6. avatar

    Par défaut un noyau à des réglages conservateur afin notamment d’être stable, et quasiment adapté à tous les besoins.
    Le fait d’avoir plus de 1000000 fichiers dans seulement un répertoire indique que l’utilisation n’est pas standard. Il faut donc utiliser des méthodes plus complexes, afin d’exploiter pleinement ce comportement hors normes.

    Il faut aussi savoir comment un programme est fait. Si tu disposes de 2 fichiers dans un répertoire, un “rm *” ne fera que “rm fichier1 fichier2″
    Si tu utilises cette commande avec un million de fichier cela donnera
    “rm fichier1 … fichier1000000″

    * 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!

    >C’est déjà super bien de savoir qu’une ligne de commande c’est dans >démarrer/exécuter! Seulement toi je pense que tu dois avoir d’autres > combines pour y accéder non?

    La c’est sous windows et j’ai presque envie de dire que sous windows le shell n’est pas obligatoire.

    Par contre sur un système unix, pour exploiter toute sa puissance, le shell est de facto obligatoire.

  7. avatar

    @jdb : merci d’avoir répondu :) c’est gentil

  8. avatar

    Pouarf, à vos souhaits :eek2:
    En tout cas, bravo Paul, je commence à m’y faire ;)

  9. avatar

    Je me suis inscrite LOL :roll: :oui:

  10. avatar

    @jdb : “Par contre sur un système unix, pour exploiter toute sa puissance, le shell est de facto obligatoire.” -> Par contre sur un système unix, pour exploiter toute sa puissance, des litres de coca sont de facto obligatoires :non:


    @Caro™ : Ce jdb, quel homme ! T’es sous le charme hein :roll: :lover: :mrgreen:


    @lucy07 : J’vais venir me faire flageller jusque sur mon propre blog :lol:

  11. avatar

    @Paul : j’croyais que tu avais arrêté le coca! :shock:
    Bah au moins il a répondu à mes questions :)! Ahah
    Bisou Paul (<—- t’as au moins gagné un bisou encore!!!)

  12. avatar

    Y’a une méthode en utilisant ‘xargs’ également qui se rapproche de la méthode liée à la commande ‘find’.

Laisser un commentaire

Connexion?

Ne sera pas publiée

;;) ;) :D :) :(