[Perl] Cherc des patterns dans +ieurs fichier

[Fermé]
Signaler
-
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
-
Salut,
Ultra débutant en Perl, je tente de faire un petit script de recherche de patterns/messages dans des fichiers C.

voici un extrait de mon script:
@files contient tous les fichiers C à scanner (path complet)
@msg_id contient une liste de messages, séparés par un saut de ligne
(genre
MON_MESSAGE_1
MON_MESSAGE_2
etc...),
y en a 2-3000 à peu près.

Et il faut que j'associe un msg_id avec un fichier C.
Donc faut que je parcours chaque fichier C pour chaque msg_id...

Mon algo est surement foireux, je débute...

Mes tableaux sont ok, le seul souci, c'est que le print qui affiche qqchose lorsque la recherche a trouvé un des msg ne marche pas...

# Run msg_id search through each file
foreach $file (@files)
{
# Parse C file to find MSG_ID
print "\n\t$file";

foreach $msg_id (@msg_id)
{
open (SRC_FILE, "$file");
while(<SRC_FILE>)
{
if(/$msg_id/)
{
# J'ai trouvé !
print "\n\t$msg_id --> $file";
}
}
close (SRC_FILE);
}
}

Merci pour votre aide !

Benoit

22 réponses

Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
Salut,

j'ai une bonne et une mauvaise nouvelle pour toi

la bonne nouvelle
je veux bien t'aider :-))

la mauvaise nouvelle
Et il faut que j'associe un msg_id avec un fichier C.
Donc faut que je parcours chaque fichier C pour chaque msg_id...


je ne comprends pas ce que tu veux.
donne moi un exemple concret.
merci.
Salut !
Merci pour la bonne nouvelle :)

J'ai un serveur avec des fichiers C un peu partout dans des repertoires différents. J'ai fait un 'find' et j'ai stocké tous les noms de fichiers.C et leur chemin dans la variable @files.

De l'autre coté, j'ai une liste de messages (des chaines de caractères) dans un fichier txt:
MON_MESSAGE_1
MON_MESSAGE_2
...
Toutes ces chaines de caractères sont stockées dans @msg_id ( j'ai fait un open puis stocké chaque message dans le tableau)

Dans les fichiers C, je vais utiliser ces messages ( genre en paramètre d'une fonction, ce sont des define)

Il faut que j'arrive à savoir ou sont utilisé mes messages, dans quel fichier C.

Donc pour chaque fichier C que j'ai dans ma liste, il faut que je le parcours pour savoir si l'un de mes messages s'y trouve ou pas.

Si l'un de mes messages s'y trouve, il faut que je crée un fichier de sorti ou j'aurai au final:
MON_MESSAGE_1 ---> fichier_toto.c
MON_MESSAGE_2 ---> fichier_titi.c
etc..

Donc pour chaque fichier C
je le parcours et je cherche si je trouve l'un de mes messages.
je fait un open/close à chaque fois car je sais pas comment on peut parcourir plusieurs fois le meme handler de fichier.
et je suis pas le rois non plus des expressions régulières...

J'espère que j'ai été plus clair !

Merci
Benoit
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
Salut,


Toutes ces chaines de caractères sont stockées dans @msg_id ( j'ai fait un open puis stocké chaque message dans le tableau)

tu récupères d'où c'est messages?
comment ça tu as fait un open?

@msg_id contient une liste de messages, séparés par un saut de ligne
(genre
MON_MESSAGE_1
MON_MESSAGE_2


Ca c'est faux. Le fait que tu affiches les éléments du tableau ne veut pas dire que les éléments sont separées par un saut de ligne

Un tableau contient une liste, dans ton cas se sont de chaînes de caractères qui peuveunt avoir un saut de ligne à la fin)

affiche ce que te donne

print "$msg_id[0]";
et
print "$msg_id[0]\n";
et
@ascii =  unpack("C*", $msg_id[0]);
print "@ascii\n";
--
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
Ca donne un script comme ça
#!/usr/bin/perl

# donc dans le script tu mets juste la partie où
# tu obtient 
#@msg_id contient une liste de messages, séparés par un saut de ligne 


print "$msg_id[0]";
print "$msg_id[0]\n";
@ascii =  unpack("C*", $msg_id[0]);
print "@ascii\n";

__END__
Merci pour ton aide !

Désolé de pas pouvoir te fournir tout le script, le reste est un peu confidentiel, je suis au taf...

Quand je parlais de @msg_id, oui, j'ai mélangé le contenu de mon fichier temporaire ou ya des sauts de lignes et ce qu'il ya dans le tableau !

ta ligne qui extrait l'ascii est interressante car je vois que les derniers caractères sont 10(LF) et 13 (CR).
CR, c'est un retour de ligne, LF aucune idée.

Voici comment je construis ce tableau:

open (INFILE, "my_file.txt") || die ("Error when trying to open input file");

my @msg_id;
my $msg_id;

#Get msg ID and put them into output file
while(<INFILE>)
{
if (/<MSG>/)
{
if(/,/)
{
push @msg_id, $';
#print OUTFILE $';
}
}
}

Dans le message source, mes messages sont stockés comme ceci:
<MSG>78941,MON_MESSAGE_1
<MSG>4875,MON_MESSAGE_2
etc...
les deux if sont pas terribles, doit y avoir mieux !

donc après ces lignes, j'ai mon tableau de messages.
Mais y a 2 caractères en trop (10 et 13).
Je peux faire 2 chomp consécutifs, mais c'est vilain, je pense qu'il faut corriger le problème à la source !

et je vais m'inscrire à un training perl, ça me fera pas de mal :)

Merci !
benoit
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
<MSG>78941,MON_MESSAGE_1
<MSG>4875,MON_MESSAGE_2


En fait, tu dois obtenir
MON_MESSAGE_1
MON_MESSAGE_2
etc.


ou

MON_MESSAGE_1 - c'est le 1er élément du tableau
MON_MESSAGE_2 - c'est le 2ème élément du tableau
etc.

C'est ça?
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
ta ligne qui extrait l'ascii est interressante car je vois que les derniers caractères sont 10(LF) et 13 (CR).
CR, c'est un retour de ligne, LF aucune idée.


Donc tes lignes se finissent avec CarriageReturn(13) et LineFeed(10)
Les lignes sous GNU/Linux se finissent avec LineFeed(10) ou \n

Lit les commentaires
while (<INFILE>){
  s/\r//;
  chomp;
# je suppose que la ligne commence avec <MSG>
# qu'après <MSG> il y a toujours des chiffres
# et ensuite une virgule
# et que tu as toujours MON_MESSAGE_QUELQUECHOSE
# si jamais au lieu de MON_MESSAGE_1
# tu as n'importe quoi ça ne va pas marcher
  next unless /^\<msg\>\d+\,(\w+)/i;
  push @msg_id, $1;
}
--
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
Encore une chose.

Il faut eviter d'utiliser $' ($POSTMATCH) pour des raisons des performances.

J'avoue que je n'ai pas suivi le coût d'utilisation de cette variable sur la dernière version de Perl.
Bon, bien c'est nikel, ça marche super bien !
Merci beaucoup !

J'aurai une dernière question :
Pour parcourir plusieurs fois le meme fichier, je fais un open/close à chaque fois ? ou il ya moyen de faire un reset du pointeur sur le fichier pour qu'il revienne au début ?

Encore merci!
Benoit
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
Pour parcourir plusieurs fois le meme fichier, je fais un open/close à chaque fois ? ou il ya moyen de faire un reset du pointeur sur le fichier pour qu'il revienne au début ?

Je ne vois pas pourquoi tu dois parcourir plusieurs foit le même fichier.
Une seule fois(et bien :-)) ça suffit.
en fait, je le parcours plusieurs fois car je boucle sur les messages.
Donc je parcours le fichier pour voir si je trouve MON_MESSAGE_1, puis je re-parcours pour voir si je trouve MON_MESSAGE_2, etc...

Je vais réfléchir à comment je peux optimiser ça, et fouiller un peu dans la doc Perl!
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
Mais non, il ne faut pas faire comme ça

Il faut ouvrir le fichier un seule fois et ensuite tester le contenu de @msg_id sur le fichier

J'ai besoin de savoir 2 choses
- les messages sont uniques?
- les noms de fichiers sont uniques?
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
Quelque chose comme ça
my %h;

foreach my $file(@files){
  open F_LIRE,$file or warn "E/S : $!\n";
    while(<F_LIRE>){
      foreach my $message (@msg_id){
        $h{$message} = $file if /$message/;
      }
    }
  close F_LIRE;
}

print "$_ ---> $h{$_}\n" foreach (sort keys %h);
les messages sont uniques, mais peuvent apparaitrent plusieurs fois dans un meme fichier C.
Les fichier C sont uniques.

En fait, au final, il faudrait que je génère un fichier txt dans ce genre:

MON_MESSAGE_1 file1.c file78.c
MON_MESSAGE_2 file1.c file963.c file78456.c
etc...

Ca me donne un rapport pour savoir pour chaque message, dans quel(s) fichier(s) C ils sont utilisés.

Merci, je vais ameliorer mon algo de recherche dans les fichiers!

Pour info, je suis plutot un spécialiste en C embarqué (dans les coeur ARM,Freescale,...). Donc la manip des fichiers, c'est nouveau pour moi :-), j'ai pas encore les automatismes.

Benoit
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
essaie comme ça
my %h;

foreach my $file(@files){
  open F_LIRE,$file or warn "E/S : $!\n";
    while(<F_LIRE>){
      foreach my $message (@msg_id){
        push @$h{$message},$file if /$message/;
      }
    }
  close F_LIRE;
}

print "$_ @$h{$_}\n" foreach (sort keys %h);
le compilo fait la gueule sur le 'push'.
il me dit qu'il veut un tableau en entrée, et pas un hash slice.
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
essaie
my %h;

foreach my $file(@files){
  open F_LIRE,$file or warn "E/S : $!\n";
    while(<F_LIRE>){
      foreach my $message (@msg_id){
        push @{$h{$message}},$file if /$message/;
      }
    }
  close F_LIRE;
}

print "$_ @$h{$_}\n" foreach (sort keys %h);

A savoir que je n'ai pas testé.
Je n'ai pas Perl au boulot.
J'ai remarqué un truc marrant,
mon ancien algo (j'ouvre et je parcours le fichier pour chaque message..) s'execute plus vite que le nouveau (celui que tu m'as écrit).
Bizarre non ?
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
Oui, parce que moi je stocke dans un hash vu que tu veuilles obtenir

MON_MESSAGE_1 file1.c file78.c
MON_MESSAGE_2 file1.c file963.c file78456.c


A savoir que tu fait nbmessages * nbfichiers appels système pour chaque fichier * nblignes de chaque fichier, et moi je fait un seul appel système pour chaque fichier * nblignes de chaque fichier
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 554
avec ton script voir message °1 tu obtiens
MON_MESSAGE_1 file1.c
MON_MESSAGE_1 file78.c 
MON_MESSAGE_2 file1.c
MON_MESSAGE_2 file963.c
MON_MESSAGE_2 file78456.c
et tu as demandé
MON_MESSAGE_1 file1.c file78.c 
MON_MESSAGE_2 file1.c file963.c file78456.c 
--
lami20j