Sed : Argument list too long

Résolu
Salut,
Et voilà je continue à galèrer. :p
Cette fois c'est la commande sed, qui m'empêche de faire ce que je veux. (encore des limitations)
Je veux lancer une commande qui touche un peu trop de fichiers semble-t-il :
sed -i 's#bateau #maison #' ../*/*/*/*

Mais bon je ne peux pas faire autrement. :D

Lors du lancement je reçois un message d'erreur :
bash: /bin/sed: Liste d'arguments trop longue


J'ai vu une histoire de "find" ou "xargs" mais bon je n'y arrive pas.
Si quelqu'un a une solution. :)
Thx.. ou mono
Configuration: Linux
Firefox 3.0.10

34 réponses

Résumé de la discussion

Problème central : l'exécution de sed -i pour remplacer 'bateau' par 'maison' sur un grand nombre de fichiers échoue avec l'erreur 'Liste d'arguments trop longue'. Plusieurs réponses proposent d'utiliser find ou xargs afin de limiter le nombre de fichiers traités et d'appliquer sed sur chaque fichier indépendamment, notamment en ciblant des extensions comme '.txt'. D'autres évoquent le regroupement des remplacements ou l'emploi de Perl, tout en discutant des coûts et des performances lorsque 25 dossiers et 50 000 commandes sont en jeu. En dernière nuance utile, une approche pratique consiste à tester sur un petit lot, puis combiner find et xargs pour limiter les fichiers à traiter et évaluer rapidement l'impact avant l'exécution à grande échelle.

Bobot (l’IA à votre service)
  1. Modérateur
    Salut,

    Par exemple
    ls ../*/*/*/* | xargs sed -i 's#bateau #maison #'
    1. Salut et merci pour la réponse. :)
      Cependant :
      bash: /bin/ls: Liste d'arguments trop longue
      sed: pas de fichiers en entrée
      
      1. Modérateur
        Re,

        Essaie
        find ../ -type f -exec  sed -i 's#bateau #maison #' {} \;
        1. Je teste.
          Ca à l'air de marcher, Merci.
          (Ca risque de mettre du temps pour vérifier si tout se passe bien)
          1. Cool ça marche. Mais je n'y comprend rien :).
            Il faut que je lance :
            sed -i 's#bateau #maison #' ../*/*/*/*

            et
            sed -i 's#bateau #maison #' ../*/*/*/*/*
            (avec un /* de plus que l'autre)
            Est ce que :
            find ../ -type f -exec  sed -i 's#bateau #maison #' {} \;

            peut remplacer les deux ?
            1. Je répond à ma propre question : OUI !!!!!! :p
              Merci pour tout.
              1. Modérateur
                Re,

                Tu as bien répondu ;-)

                De rien ;-))
            2. Modérateur
              Re,

              De toute façon tu veux traiter tous les fichiers de répertoire parent.
              Pourquoi pas utiliser le chemin complet de répertoire parent?

              De toute façon ce ça que ../ fait dans dans le find.
              Tu n'as pas besoin de tous ces étoiles

              Pour plus de clarté je te conseille de mettre le chemin complet de répertoire parent
              Dans ce répertoire tu n'as que des fichiers texte? Les fichiers ont une extension ou pas (.txt par exemple)
              Je ne pense pas que c'est ça que tu veux.
              find /chemin/complet -type f -exec  sed -i 's#bateau #maison #' {} \;
              1. Hum voilà. En fait ça fonctionne parfaitement mais le premier fichier SH modifie également les autres fichiers SH. :D
                Comment le limiter aux fichiers avec extension .txt par exemple ?
                1. Modérateur
                  Salut,
                  find /chemin/complet -type f -name "*.txt" -exec  sed -i 's#bateau #maison #' {} \;
                  1. OK merci. :)
                    Et un nouveau problème fun mais à part tout changer je ne vois pas de solution :
                    D'après de rapides estimations, mon programme met 1 an et demi pour s'executer... :o
                    Je crois que ça ne va pas le faire...

                    Une idée pour limiter sed aux 10 dernières lignes avant les dix dernières lignes du fichier ? (Je crois que je demande un peu trop à la machine là :s)
                    1. Modérateur
                      Peut être voir avec un autre programme comme "Perl".

                      Une idée pour limiter sed aux 10 dernières lignes avant les dix dernières lignes du fichier ?
                      Hum... on va dire que techniquement c'est possible (plus particulièrement avec "ed" plutôt que "sed"), mais ça serait encore plus lourd, donc plus long ;-((

                      Édit : Pour te donner une idée avec "ed" :
                      [tmpfs]$ cat plop
                      Ligne 1
                      Ligne 2
                      Ligne 3
                      Ligne 4
                      Ligne 5
                      Ligne 6
                      Ligne 7
                      Ligne 8
                      Ligne 9
                      Ligne 10
                      Ligne 11
                      Ligne 12
                      Ligne 13
                      Ligne 14
                      Ligne 15
                      
                      [tmpfs]$ ed -s plop <<< $'H\n,-10;+5 s/Ligne/& n° /\n,w'
                      
                      [tmpfs]$ cat plop
                      Ligne 1
                      Ligne 2
                      Ligne 3
                      Ligne 4
                      Ligne n°  5
                      Ligne n°  6
                      Ligne n°  7
                      Ligne n°  8
                      Ligne n°  9
                      Ligne n°  10
                      Ligne 11
                      Ligne 12
                      Ligne 13
                      Ligne 14
                      Ligne 15
                      [tmpfs]$
                      ;-))
                  2. Modérateur
                    Salut,

                    Tu as combien de fichiers?
                    find /chemin/complet -type f -name "*.txt" | wc -l
                    Tu as combien de remplacements à faire dans tes fichiers?
                    find . -name '*.txt' -exec grep -c bateau {} \;|awk '{SUM += $1}END{print SUM}'
                    
                    1. 50 000 commandes sed ciblant chacune dans les 5.2 Go de données. :'(
                      Des images dans le tas :p
                      1. Modérateur
                        Re,

                        Affiche le résultat des commandes que je t'ai donné ;-)

                        mon programme met 1 an et demi pour s'executer
                        Ici on parle d'une commande.
                        Ton programme contient autre chose?!

                        Tes estimations se basent sur quoi?
                        J'ai traiter des fichiers de 600 Mo et je n'ai pas passer des heures pour le faire, donc 5 Go dans 1 an et demi c'est un peut trop quand même.

                        1. (En fait c'est un prog en C qui ecrit un fichier .sh qui s'éxecute, celui-ci est constitué de 50 000 commandes de modifications de type sed, mais si l'une d'elle devient plus rapide ça affectera le reste, qui sera modifié également)

                          find /chemin/complet -type f -name "*.txt" | wc -l

                          me rend 34 148

                          Tu as combien de remplacements à faire dans tes fichiers?
                          Alors euh un seul par commande dans chaque dossier après le ../

                          En fait il y a 25 dossier (au niveau du chemin ../). Et dans chaque dossier je ne rencontre cette suite qu'une seule fois. Possible de lui dire de passer au dossier d'après s'il a trouvé la chaine ? :p
                          1. Il y pense toujours à la deuxième commande. Elle va arriver surement ^^
                            Théoriquement ça sera 25. :)
                            [Edit]Confirmation le résultat est 25 :)

                            Pour l'estimation ben, j'ai chronométré le temps d'éxecution d'une commande sed et j'ai multiplié le tout par le nombre de commandes. :D
                            1. Modérateur
                              Re,

                              Impossible.
                              La deuxième commande doit afficher le nombre de lignes qui contient le mots bateau (ce le mot à remplacer).

                              Donc si tu as 30 000 fichiers et qu'il y a un remplacement par fichier tu dois avoir le résultat de la deuxième commande au moins égal avec le nombre de fichiers.
                              1. Modérateur
                                Re,

                                Un exemple chez moi sur 5 fichiers
                                $ pwd
                                /home/lami20j/toolong
                                $ ls -1
                                fichier1.txt
                                fichier2.txt
                                fichier3.txt
                                fichier4.txt
                                fichier5.txt
                                $ ls -1 | wc -l
                                5
                                $ find . -name '*.txt' | wc -l
                                5
                                $ find . -name '*.txt' -exec grep -c bateau {} \;|awk '{SUM += $1}{print SUM}'
                                23
                                46
                                69
                                92
                                115
                                $ find . -name '*.txt' -exec grep -c bateau {} \;|awk '{SUM += $1}END{print SUM}'
                                115
                                
                                1. Explication du dessus en détail :

                                  ../ contient
                                  dossier1
                                  dossier2
                                  dossier3
                                  .
                                  .
                                  .
                                  dossier24
                                  dossier25

                                  dans chacun de ces dossiers, il y a d'autres dossiers etc ... et des fichiers .txt à modifier
                                  cependant le mot "bateau" (c'est un exemple évidemment) ne revient qu'une seule fois par dossier.

                                  Exemple : Dans "dossier1" il n'y a qu'un seul fichier .txt qui contient le mot ''bateau" et en plus ce mot n'est présent qu'une seule fois.
                                  1. Modérateur
                                    Salut,

                                    Je n'ai pas besoin d'exemples. Tu as un cas concret. Donc tu as besoin de précision.

                                    Si un seul fichier contient le mot bateau et en plus une seule fois alors je ne vois pas pourquoi tu as besoin de remplacer les 10 dernières lignes avant les 10 dernières.
                                    Pour moi ton cas n'est pas clair et en ce cas je ne peux pas t'apporter de l'aide.

                                    En plus des 2 commandes que je t'ai donné et tu ne veux toujours pas m'afficher le résultat, installe le paquet tree et ensuite tape la commande
                                     tree -P "*.txt" -o log
                                    Tu peux mettre le fichier compressé sur cjoint.com
                                    • 1
                                    • 2