Forum Programmation.perl faire fonctioner Code sur plusieurs Fichiers se trouvant tous dans un dossier

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
-1
21
avr.
2015

j'ai un Code-Perl qui fonctione sur plusieurs fichiers-XML, mais pour cela je dois donner sur mon editor-perl la commande C:perl code.pl A.xml B.xml C.xml D.xml et j'obtient un resultat, comment faire si j'avais millier de fichier-XML et j'aimerai que le code soit a mesure de traiter tous les fichiers-XML tout seul, sans toute fois me mettre a tape sur mon Editor-perl tous les noms de mes fichiers-XML.

  • # perlmonks says

    Posté par  . Évalué à 2.

    http://www.perlmonks.org/?node_id=691699

    En gros 3 façons:
    La première (glob) est intégrée et te permet de spécifier un truc du genre /mon/path/*.xml

    La suivante (File::Util) offre la récursivité si besoin (genre tu spécifies 2 arguments "perl monscript.pl --dir /mon/* -R) mais tu n'as pas par contre filtrage par pattern de nom de fichier (a moins bien sur de le faire sur le résultat retourne par File::Util)

    La troisième m'est inconnue, mais a l'air de cumuler les fonctionnalités des trois, peut-être au prix d'un effort de compréhension supplémentaire?
    Indice, ça correspondant à find (1) dans l'esprit.
    (note a moi-même : à lire quand il ne sera pas 00:10)

    Pour la gestion des paramètres dans ton script, je te conseille la lecture de http://articles.mongueurs.net/magazines/linuxmag49.html si besoin est.

    Dans tous les cas, n'oublie pas : "There's more than one way to do it"

    • [^] # Re: perlmonks says

      Posté par  . Évalué à 0.

      salut de me torture depuis des heures mais je n'avance pas. j'ai deja essaye mais ce ne fonctione pas. je sais une chose il faut utiliser le module File::Find et la subroutine &wanted
      en voici un code permetant par exemple de retrouver tous les fichiers donc les noms commence par d et t se trouvant dans un dossier (probe) sur mon ordinanteur. mais il ne m'apporte rien car j'aimerai lasser mon code s'executer sur des milliers de fichiers se trouvant tous dans un meme dossier. Pardon quelqu'un peut-il avoir une idee?

      use strict;
      use warnings;
      use XML::Twig;   
      use File::Find;
      
      my $file ='\Users\ADMIN\Documents\probe';
      
      my $FileResult = 'result.txt';
      open( my $FhResult, '>', $FileResult )or die ("Unable to open file $FileResult\n$!");
      
      find(\&wanted, $file);
      
      sub wanted {
          print $FhResult  "Found it $File::Find::dir/$_\n" if /^[d or t]/i;
      }
      • [^] # Re: perlmonks says

        Posté par  . Évalué à 0.

        personne ici ne peut m'aider a resoudre mon problem? j'ai lu les informations sur les lien envoye plus haut malheureusement cela na me permet pas d'avancer

        • [^] # Re: perlmonks says

          Posté par  . Évalué à 3.

          en même temps on est pas devin, on ne sait même pas quelle est ta plateforme de dev, ça pourrait être Solaris, un Gnu/Linux, un BSD, un GNU/Hurd, un windows avec cygwin, un windows sans cygwin, ça pourrait être du DEC, un VMS…

          Bref rien que l'OS cible fait défaut.

          Ensuite on ne sait pas si tu veux que tous les fichiers soient traités via un seul appel à la commande, ou si plusieurs appels sont acceptables.

          parce que comme solution j'ai

          • find /repertoire/ou/sont/les/fichier/xml -iname '*xml' --exec monScriptPerl.pl {}\;
          • monScriptPerl.pl $( find /repertoire/ou/sont/les/fichier/xml -iname '*xml' )
          • cd /repertoire/ou/sont/les/fichier/xml ; monScriptPerl.pl *xml

          Tu peux aussi jouer à coup de powershell si tu es sous windows, ou bêtement faire un Drag&Drop de tes fichiers sur le script :P

          Enfin si tu fait tu traitement xml sur tous les fichier à la fois j'ose espérer que tu ne fais pas du DOM.

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: perlmonks says

            Posté par  . Évalué à 0.

            je suis desole ca ne fonctione pas, et a propos que veut tu dire avec iname et je pense que c'est *.xml

          • [^] # Re: perlmonks says

            Posté par  . Évalué à 1.

            Pas sur que ça marche sans cygwin (il est sous windows) le coup de passer par ARGV.

            Windows 7 par exemple a des limitations du type si PATH a une longueur supérieure à 2048 chars, alors quasi plus rien ne marche (si les variables paths système genre C:\windows\ sont à la fin et donc ignorées ? je n'ai pas vérifié).

            Henry parle de milliers de fichiers donc ça me parait mal barré sans cygwin.

        • [^] # Re: perlmonks says

          Posté par  . Évalué à 1.

          find2perl /home/henri/xmlfolder/ -name "*.xml" > lasolutionamonprobleme.pl

          • [^] # Re: perlmonks says

            Posté par  . Évalué à 1.

            Bon je viens de capter que tu es sous Windows.
            Je pense que la suggestion de fearan sur faire ton truc en powershell est pertinente (no troll, powershell est vraiment pas mal).
            Cela dit, il semble que tu aies déjà du code en perl, et de toute façon, on est pas sur DLFP pour pousser les gens à dev en .ps.

            Erratum sur le précédent commentaire: ajoutes -type f:

            find2perl /home/henry/xmlfolder/ -type f -name "*.xml" > lasolutionamonprobleme.pl

            En gros tu as :

            use strict;
            use File::Find ();
            
            # Set the variable $File::Find::dont_use_nlink if you're using AFS,
            # since AFS cheats.
            
            # for the convenience of &wanted calls, including -eval statements:
            use vars qw/*name *dir *prune/;
            *name   = *File::Find::name;
            *dir    = *File::Find::dir;
            *prune  = *File::Find::prune;
            
            sub wanted;
            
            # Traverse desired filesystems
            File::Find::find({wanted => \&wanted}, '/home/henry/xmlfolder/');
            exit;
            
            sub wanted {
                my ($dev,$ino,$mode,$nlink,$uid,$gid);
            
                (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
                -f _ &&
                /^.*\.xml\z/s
                && print("$name\n");
            }
            

            Tu crées une belle fonction processXML :

            sub processXML ($) {
                print $_."\n";
            }
            

            et tu remplaces la fonction wanted par:

            sub wanted {
                my ($dev,$ino,$mode,$nlink,$uid,$gid);
            
                (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
                -f _ &&
                /^.*\.xml\z/s
                && processXML($name);
            }
            

            C'est en récursif, je n'ai pas cherché comment désactiver la récursivité.

            Pour mettre le path de recherche des fichiers xml en argument de lasolutionamonprobleme.pl, réfères toi à l'article des mongueurs sus-mentionné.

            P.S.1.: La solution est présentée comme telle pour plus de clarté, mais tu peux évidemment faire ton traitement xml dans la fonction wanted.

            P.S.2. : [à prendre avec des pincettes] Ton affirmation sur "tous les fichiers donc les noms commence par d et t" a l'air incorrecte, il s'agirait en fait de tous les fichiers ou dossiers contenants un d ou un t (ainsi que tous les enfants si il s'agit d'un dossier) et ce de manière récursive?
            par exemple, ca retourne ca sur mon ~:
            Found it /home/warwick/.icedove/dhi10c6d.default/extensions/rikaichan-jpfr@polarcloud.com/chrome/rikaichan-jpfr.jar

            J'utilise une syntaxe PCRE pour mes regex et je suis un peu paumé avec ton exemple. Chez moi, la syntaxe suivante fonctionne:
            /^[d|t].*\z/si (le i pour conserver ton case insensitive).

            P.S.3.: Tu n'as pas fermé ton filehandle dans le bout de code que tu donnes.
            https://en.wikipedia.org/wiki/Handle_leak

            P.S.4.: Tu codes avec le compte admin ?

            P.S.Vita.: Non, je ne fais aucunement de la pub à Sony.

            P.S.CoinCoin.: J'espère que j'ai pas passe une partie de ma soirée après 12h au taff pour ne pas répondre à ta question…

          • [^] # Re: perlmonks says

            Posté par  . Évalué à 0.

            Salut Warwick, malheureusement cela ne fonctione pas je pense qu'il faut que je vous persente a quoi ressemble mon code-perl qui est dans un dossier avec les fichiers-XML comment faire a ce que ce code fonctionne automatiquement sur les fichiers-XML parceque j'en ait plusieurs Milliers de fichiers-xml

            #!/usr/bin/perl                      
            use strict;
            use warnings;
            use XML::Twig;   
            use Text::CSV;                  
            
            my @files = @ARGV or die 'No files';    
            my $FileResult = $ARGV[1] || 'result.csv'; 
            
            #Ausgabedatei wird geöffnet und geprüft
            
            open( my $FhResult, '>', $FileResult ) or die("Unable to open file $FileResult\n$!");
            my $twig2= XML::Twig->new(    
                    twig_handlers => { 
                            'Parameter' => sub { 
            
                                    my $attr_value = $_->{'att'}->{'value'} // 'fault';  
                                    print $FhResult $attr_value . ",";
                            },
                    },
            );
            
            print $FhResult( (split('_', "\n$file2",2))[0] . ',' ); 
            $twig2->parsefile($file2);
            
            close $FhResult;
            • [^] # Re: perlmonks says

              Posté par  . Évalué à 1.

              Je ne peux pas t'aider sur Twig (il est minuit 15 chez moi, je dois aller au lit).
              Essaye ca:

              #!/usr/bin/perl                      
              use strict;
              use warnings;
              use XML::Twig;   
              use Text::CSV;                  
              use File::Find;
              
              
              my $FileResult = $ARGV[1] || 'result.csv'; 
              my $FhResult;
              
              my $folder ='.';
              my $twig2= XML::Twig->new(    
                  twig_handlers => { 
                      'Parameter' => sub { 
                          my $attr_value = $_->{'att'}->{'value'} // 'fault';  
                          print $FhResult $attr_value . ",";
                      },
                  },
              );
              
              sub newwanted {
                  my ($dev,$ino,$mode,$nlink,$uid,$gid,$name);
              
                  (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
                  -f _ &&
                  /^.*\.xml\z/s
                  && processXML($name);
              }
              
              sub processXML ($) {
                  print $FhResult( (split('_', "\n$_",2))[0] . ',' ); 
                  $twig2->parsefile($_);
              }
              
              open( $FhResult, '>', $FileResult ) or die("Unable to open file $FileResult\n$!");
              
              find({
                 wanted   => \&newwanted,
              }, $folder);
              
              close $FhResult;
              

              Ca retourne ceci dans results.csv chez moi:

              $ cat result.csv 
              
              4.xml,
              1.xml,
              3.xml,
              2.xml,
              
              • [^] # Re: perlmonks says

                Posté par  . Évalué à 0.

                Teste malheureusement ne fonctione pas

              • [^] # Re: perlmonks says

                Posté par  . Évalué à 0.

                je ne sais pas si nous somme entrain de nous comprendre car le code donc jai donne plus haut parse le fichiers-xml, mais pour cela il me faut alle dans mon editor perl ecrire les noms de tous mes fichiers, malheureusement j#en ai des milliers de fichiers-xml, et j'aimerai que ce code soit a mesure de retrouver tous le fichiers se trouvant dans un dossier et en suite naturement les parser, sans toute fois que je met a taper dans mon editor le nom de milliers de fichiers. c'est cela mon probleme.
                Le veritable probleme c'est que je possede un Millier de Fichier-XML, si je n'en possedait que 4 ou 6 j'aurai tapez les noms dans mon editor-perl et j'aurai recu un resultat a l'immediat

                en quelque sorte je pourrai resume de la sorte:

                1-(Perl-script + Fichiers-XML) sauvegarder dans un dossier sur mon Ordi
                2- Perl-script cherche les fichiers-XML se trouvant dans le dossier
                3- perl-script traite (parser) les fichiers_xml
                4- perl-script me retourne le result du parsage.

                • [^] # Re: perlmonks says

                  Posté par  . Évalué à 2.

                  j'aimerai que ce code soit a mesure de retrouver tous le fichiers se trouvant dans un dossier et en suite naturement les parser, sans toute fois que je met a taper dans mon editor le nom de milliers de fichiers. c'est cela mon probleme.

                  et c'est exactement les diverses solutions qui te sont proposées mais que tu ne sembles pas avoir comprises ou implementées.

                  Solution 1 : avec le shell (batch dos, powershell), faire une boucle qui va faire :
                  - pour chaque fichier .xml
                  -- execute perl lecode.pl lefichier

                  Solution 2 : avec perl
                  - dans ton script perl, ajouter une fonction qui prend les fichiers dans le ARGV de 1 à n et les mets dans le tableau de fichier à traiter @FILES
                  -- puis, faire une boucle qui, tant que tu as des fichiers, execute le parsage
                  - ensuite lancer ton script avec perl lecode.pl *.xml

                  Solution 3 : avec perl, en utilisant perl find, qui va faire sensiblement la meme chose que Solution2,
                  simplement c'est perl qui va chercher les fichiers dans l'arborescence, et les donnés au tableau de fichier @FILES
                  qui devra de toute facon faire une boucle tant qu'il y a des fichiers

                  • [^] # Re: perlmonks says

                    Posté par  . Évalué à 0.

                    Salut Neox,
                    j'ai pas correctement saisi les Propositions mais c'est cela que j'essaye de comprendre mais quand j'excecute le code il me revoit une erreur donc je cherche depuis hier une explication clair a cela:
                    voila l'erreur qu'il me mensione.

                    C:\Users\ADMIN\Documents>perl new2.pl
                    Undefined subroutine &wanted::wanted called at C:/strawberry/perl/lib/File/Find.
                    pm line 691.

                    • [^] # Re: perlmonks says

                      Posté par  . Évalué à 2.

                      Undefined subroutine &wanted::wanted called at C:/strawberry/perl/lib/File/Find.pm line 691.

                      comme le port salut, c'est marqué dessus. ;)

                      dans ton programme tu sembles appeler une subroutine wanted qui ne semble pas exister/definie par ton code (undefined)

                      • [^] # Re: perlmonks says

                        Posté par  . Évalué à 0. Dernière modification le 23 avril 2015 à 13:18.

                        exactement quand j'ai eu cela j'ai ecrit use wanted mais il la continue a me signaler la mm erreur

                        #!/usr/bin/perl                      
                        package wanted;
                        use strict;
                        use warnings;
                        use XML::Twig;   
                        use Text::CSV;                  
                        use File::Find;
                        use wanted;
                        
                        
                        my $FileResult = $ARGV[1] || 'result.txt'; 
                        my $FhResult;
                        
                        my $folder ='.';
                        my $twig2= XML::Twig->new(    
                            twig_handlers => { 
                                'Parameter' => sub { 
                                    my $attr_value = $_->{'att'}->{'value'} // 'fault';  
                                    print $FhResult $attr_value . ",";
                                },
                            },
                        );
                        
                        File::Find::find({wanted => \&wanted}, 'C:\Users\ADMIN\Documents');
                        exit;
                        
                        sub newwanted {
                            my ($dev,$ino,$mode,$nlink,$uid,$gid,$name);
                        
                            (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&
                            -f _ &&
                            /^.*\.xml\z/s 
                            && processXML($name);
                        }
                        
                        sub processXML ($) {
                            print $FhResult( (split('_', "\n$_",2))[0] . ',' ); 
                            $twig2->parsefile($_);
                        }
                        
                        open( $FhResult, '>', $FileResult ) or die("Unable to open file $FileResult\n$!");
                        
                        find({
                           wanted   => \&newwanted,
                        }, $folder);
                        
                        close $FhResult;
                        • [^] # Re: perlmonks says

                          Posté par  . Évalué à 2.

                          lire et comprendre un tuto plutot que d'appliquer "betement" les lignes qu'on te donne (sinon file nous ton "salaire", on fera ton boulot ;) )

                          exemple, je vois dans ton code :

                          File::Find::find({wanted => \&wanted}, 'C:\Users\ADMIN\Documents');
                          exit;

                          tu appelles donc File::Find::find avec un parametre &wanted
                          qui n'existe pas

                          plus bas, bien apres le "exit;" qui arrete ton programme

                          tu definis une subroutine &newwanted

                          que tu n'appelles qu'une seule fois, dans le find(wanted => &newwanted)

                          bref on t'as donné des pistes, à toi de les exploiter correctement, et tu es en stage, tu dois donc avoir un 'maitre de stage' qui doit aussi pouvoir t'aider.

                          pour memoire avant de programmer, il faut (d)ecrire son programme en "francais" ou dans ta langue maternelle, on appelle ca l'alogritme, dans ton cas voici ce que j'ecrirais comme logique :

                          • definir le dossier de depart
                          • lister les fichiers contenu dans le dossier
                          • faire une boucle sur cette liste, tant que j'ai un fichier à traiter -- traiter le fichier en cours

                          apres tu peux faire des fonctions, des sub si tu veux,
                          mais faut deja respecter la logique de la solution à ton probleme sera un bon point.

                          • [^] # Re: perlmonks says

                            Posté par  . Évalué à 0.

                            NeoX,
                            Je suis en Stage j'apprend Perl je ne m'y connais pas avec Perl, je m'y connais un peu plus avec Java, malheuresement ca n'a pas ete facile de trouve un stage en JAva, j'ai eu cette proposition et je ne pouvais refuser, ccar comme je l'ai dit pour obtenir une plce c'est pas facile.
                            Mon Maitre de stage est un System Administrateur il n'est pas un programmmeur c'est moi qui lui fait meme decouvrir des choses en Perl. Donc s'il te plait ne soit pas fache apres moi. je peu aussi comprendre que toi ou d'autre personne soit un peut dessus des questions que je pose. Comme je l'ai dit je m'y connais dans le developpement de Pages internet en Java.

                            • [^] # Re: perlmonks says

                              Posté par  . Évalué à 1.

                              Voila ce que j'en penses.

                              perl -e '@a=split "","Bqqsfoet!b!mjsf!pv!wb!gbjsf!vo!qjdojd/";$_=chr(ord($_)-1) for @a;$d=join "",@a;print "$d\n"'
                              
                            • [^] # Re: perlmonks says

                              Posté par  . Évalué à 2.

                              connaitre un langage de programmation, c'est deja une base,
                              et c'est pratique pour en apprendre d'autres.

                              et que tu l'ecrives en java, en C, en python, ou en perl,
                              la logique va etre la meme

                              quand on te dis
                              - recuperer la liste des fichiers
                              - faire une boucle tant qu'il y a des elements
                              -- traiter l'element courant

                              il faut que ton code ressemble à ca
                              - une recuperation de la liste des fichiers
                              - une boucle
                              -- un traitement

                              tu avais reussi à faire :
                              - une liste de 3 ou 4 fichiers
                              - une boucle sur cette liste
                              -- le traitement sur chaque element de la liste

                              il ne te reste donc qu'à modifier le remplissage de la liste
                              et c'est la partie qu'on essaie de t'expliquer avec Find, ou avec ARGV[1] jusqu'à ARGV[n]

            • [^] # Re: perlmonks says

              Posté par  . Évalué à 2.

              ha ben avec ça on est mieux barré va donc partir sur du powershell, d'ou l'intérêt de précisier un minimum le système d'exploitation.

              ls *.xml | %{ C:\perl\perl.exe progPerl.pl $_.FullName result.csv }

              et un petit changement dans le open pour avoir >> au lieu de >

              et avec C:\perl\perl.exe qui est le chemin complet vers perl.exe et progPerl.pl qui est le chemin complet vers le script perl

              si tu as des espaces dans les noms de programme (typiquement C:\Program Files\Editor\perl5.4\perl.exe il faut mettre des "" autour du nom de programme et un &avant le premier ", si il y a des espace dans le chemin du programme perl il faut juste mètre des "" autour.

              Il ne faut pas décorner les boeufs avant d'avoir semé le vent

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.