[Perl] Transformer code shell en perl

Transformer code shell en perl [Perl] - Perl - Programmation

Marsh Posté le 22-06-2005 à 14:44:29    

Bonjour,
Voilà comme indiquer dans le titre, je dois "traduire" un code shell en perl
Prb je rame sec (oui je connait pas perl, apprentissage sur le tas)
 
voici le code shell:
 
[quote]
HOME_STATS=.
TYPECFG=${HOME_STATS}/networkTypes.cfg
ITEMSCFG=${HOME_STATS}/networkItems.cfg
FLIC_LOG=${HOME_STATS}/logs
 
i=0
while IFS=':' read ip name type community ; do
        ips[$i]=$ip
        name[$i]=$name
        types[$i]=$type
        communities[$i]=$community
        i=$((i+1))
done < ${ITEMSCFG}
[/quotes]
 
Explication: ce bout de script va chercher des infos dans un fichier dont le nom est stocké ds la variable ITEMCFG, à chaque ligne du fichiers on trouve diverse infos séparées par un caractère ":"
 
Dc concernant les lignes de déclaration de variable c'est bon c'est fait (pas dur ;))
Par contre pour la boucle qui va lire dans les fichiers  :( j'ai essayé quelques truc mais bon vu mon niveau d'expérience en perl c'est pas gagné.


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 22-06-2005 à 14:44:29   

Reply

Marsh Posté le 22-06-2005 à 16:01:55    

Pour t'aider, tu peux trouver la documentation intégrale de PERL ici :
http://www.perl.org
 
Et tu peux trouver des tutoriels & FAQ ici :
http://www.developpez.net
 
 
Sinon, pour ton problème, je vais essayer de te montrer comment faire avec du code sur-commenté.
N'hésite pas à demander si tu ne comprends pas :
 

Code :
  1. #!/usr/bin/perl -w
  2. # Ces deux "use" configurent l'interpreteur en mode "severe"
  3. # Ca oblige a ecrire du code propre et, par consequent, moins
  4. # expose aux bugs.
  5. use strict;
  6. use warning;
  7. # Declaration des variables pointant vers les fichiers a lire
  8. # En PERL, la convention veut que les noms en majuscules soient
  9. # reserves aux descripteurs de fichier. On va donc les mettre en
  10. # minuscule.
  11. my $home_stats = ".";
  12. my $type_cfg = "${home_stats}/networkTypes.cfg";
  13. my $items_cfg = "${home_stats}/networkItems.cfg";
  14. my $flic_log = "${home_stats}/logs";
  15. # "dictionnaire" : une table de hachage qui va contenir
  16. # toutes les donnees lues.
  17. # Table de hachage = tableau associatif clef => valeurs
  18. my %dict;
  19. # ouverture du fichier $items_cfg
  20. open(ITEMSCFG, $items_cfg) or die "Echec ouverture de $items_cfg : $!";
  21. # Pour chaque ligne du fichier...
  22. foreach my $line ( <ITEMSCFG> )
  23. {
  24.    # nettoyage des caracteres de retour charriot
  25.    chomp $line;
  26.    # decoupage de la ligne suivant le separateur ':'
  27.    # on stocke le resultat dans les champs ad hoc
  28.    my ($ip, $name, $type, $community) = split ':', $line;
  29.    # On stocke le resultat dans notre "dictionnaire"
  30.    # Je choisis la clef = $ip, a toi de voir si une autre
  31.    # donnee est plus appropriee
  32.    # En fait ici notre hachage est un peu plus complique qu'un
  33.    # hachage normal, car ici on cree un "hachage de hachage"
  34.    $dict{$ip} = { NOM => $name,
  35.                   TYPE => $type,
  36.                   COMMUNITY => $community };
  37. }
  38. # fermeture du fichier
  39. close(ITEMSCFG);
  40. # accedons maintenant a nos donnees
  41. # Pour l'exemple, je vais acceder a ces donnees de
  42. # maniere exhaustive, avec une boucle qui va parcourir
  43. # tout le dictionnaire
  44. # traduction : pour chaque clef de notre tableau associatif...
  45. # rappel : nous avons utilise ici l'IP comme clef
  46. foreach my $ip ( keys %dict )
  47. {
  48.    # '\n' signifie : retour a la ligne
  49.    print "=[ $ip ]=\n";
  50.    print "Nom : " . $dict{$ip}->{NOM} . "\n";
  51.    print "Type : " . $dict{$ip}->{TYPE} . "\n";
  52.    print "Community : " . $dict{$ip}->{COMMUNITY} . "\n";
  53. }


Message édité par Elmoricq le 22-06-2005 à 16:05:04
Reply

Marsh Posté le 22-06-2005 à 16:06:36    

Merci beaucoup, je vais essayer de traduire la suite de mon code à partir de ca. :)


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 22-06-2005 à 16:10:39    

par contre plutot que le dictionnaire il est pas possible d'utiliser un classique tableau??


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 22-06-2005 à 16:11:04    

thurfin a écrit :

Bonjour,
Voilà comme indiquer dans le titre, je dois "traduire" un code shell en perl
Prb je rame sec (oui je connait pas perl, apprentissage sur le tas)
 
voici le code shell:
 
[quote]
HOME_STATS=.
TYPECFG=${HOME_STATS}/networkTypes.cfg
ITEMSCFG=${HOME_STATS}/networkItems.cfg
FLIC_LOG=${HOME_STATS}/logs
 
i=0
while IFS=':' read ip name type community ; do
        ips[$i]=$ip
        name[$i]=$name
        types[$i]=$type
        communities[$i]=$community
        i=$((i+1))
done < ${ITEMSCFG}
[/quotes]
 
Explication: ce bout de script va chercher des infos dans un fichier dont le nom est stocké ds la variable ITEMCFG, à chaque ligne du fichiers on trouve diverse infos séparées par un caractère ":"
 
Dc concernant les lignes de déclaration de variable c'est bon c'est fait (pas dur ;))
Par contre pour la boucle qui va lire dans les fichiers  :( j'ai essayé quelques truc mais bon vu mon niveau d'expérience en perl c'est pas gagné.


 
Je fais du Perl mais j'ai déjà fais du shell mais ça remonte un peu... :D
 
Si j'ai bien compris la boucle while, elle s'occupe de parcourir les lignes d'un fichier et de spliter chaque ligne avec le caractère ":" pour  pouvoir récupérer les valeurs : ip, name, type, community. Ensuite on les stocke dans des tableaux (si jme trompe pas sur l'interprétation du shell).
 
Voilà ce que je suggere:

Code :
  1. my @ips;
  2. my @name;
  3. my @types;
  4. my @communities;
  5. open(FIC,"chemin_de_ton_fichier" ) || die "Probleme a l\'ouverture : $!\n";
  6. $i=0;
  7. while (defined($l=<FIC> ))
  8. {
  9.    (ips[$i],name[$i],types[$i],communities[$i])=split(/:/, $l);
  10.     $i++;
  11. }
  12. close FIC;


 
Jsais pas si ça va t'aider mais bon...

Reply

Marsh Posté le 22-06-2005 à 16:13:04    

Arf si j'avais vu ton post Elmoricq j'aurais pas poster :D

Reply

Marsh Posté le 22-06-2005 à 16:17:28    

concernant le script de elmoricq j'essaye de le faire avec des tableau plutot, ca m'est plus familier comme structure et ca sera plus simple pour la suite. J'aurai besoin de savoir si je peu incrémenter un compteur à la fin de la section "foreach my $line ..." ?


Message édité par thurfin le 22-06-2005 à 16:18:13

---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 22-06-2005 à 16:18:34    

thurfin a écrit :

par contre plutot que le dictionnaire il est pas possible d'utiliser un classique tableau??


 
Si.
Sauf que tu vas devoir utiliser 4 tableaux (un pour les IP, les noms, les types et les communities).
Avec comme seul point commun leurs indices.
 
Je trouve qu'un hachage est plus adapté au besoin que tu as exposé ici, mais l'un des aspects  réputés du PERL est qu'on peut faire une chose de plusieurs manières différentes. ;)
 
Avec des tableaux :
 

Code :
  1. #!/usr/bin/perl -w
  2. # Ces deux "use" configurent l'interpreteur en mode "severe"
  3. # Ca oblige a ecrire du code propre et, par consequent, moins
  4. # expose aux bugs.
  5. use strict;
  6. use warning;
  7. # Declaration des variables pointant vers les fichiers a lire
  8. # En PERL, la convention veut que les noms en majuscules soient
  9. # reserves aux descripteurs de fichier. On va donc les mettre en
  10. # minuscule.
  11. my $home_stats = ".";
  12. my $type_cfg = "${home_stats}/networkTypes.cfg";
  13. my $items_cfg = "${home_stats}/networkItems.cfg";
  14. my $flic_log = "${home_stats}/logs";
  15. # tableaux contenant les donnees lues
  16. my (@ip_list, @name_list, @type_list, @community_list) = ();
  17. # ouverture du fichier $items_cfg
  18. open(ITEMSCFG, $items_cfg) or die "Echec ouverture de $items_cfg : $!";
  19. # un petit compteur
  20. my $count = 0;
  21. # Pour chaque ligne du fichier...
  22. foreach my $line ( <ITEMSCFG> )
  23. {
  24.    # nettoyage des caracteres de retour charriot
  25.    chomp $line;
  26.    # decoupage de la ligne suivant le separateur ':'
  27.    # on stocke le resultat dans les champs ad hoc
  28.    ( $ip_list[$count],
  29.      $name_list[$count],
  30.      $type_list[$count],
  31.      $community_list[$count] ) = split ':', $line;
  32.    # incrementation du compteur
  33.    $count++;
  34. }
  35. # fermeture du fichier
  36. close(ITEMSCFG);
  37. # accedons maintenant a nos donnees
  38. # Pour l'exemple, je vais acceder a ces donnees de
  39. # maniere exhaustive, avec une boucle qui va parcourir
  40. # tout le dictionnaire
  41. # pour tout "i" allant de 0 a "nombre d'elements de ip_list"
  42. foreach my $i ( 0..scalar(@ip_list) )
  43. {
  44.    # '\n' signifie : retour a la ligne
  45.    print "IP : $ip_list[$i]\n";
  46.    print "Nom : $name_list[$i]\n";
  47.    print "Type : $type_list[$i]\n";
  48.    print "Community : $community_list[$i]\n";
  49. }


Message édité par Elmoricq le 22-06-2005 à 16:27:22
Reply

Marsh Posté le 22-06-2005 à 16:24:03    

ok merci


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 22-06-2005 à 16:31:32    

Code :
  1. split(/:/, $l);


 je dois bien lire $i et non $1 ?


Message édité par thurfin le 22-06-2005 à 16:32:45

---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 22-06-2005 à 16:31:32   

Reply

Marsh Posté le 22-06-2005 à 16:35:23    

non en fait c bien $1 mais bon message d'erreur il veut que je face un paquage.


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 22-06-2005 à 16:43:26    

Bon ben ca marche (enfin j'ai pas d'erreur de syntaxe); merci pour tout.


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 27-06-2005 à 13:30:17    

j'ai avancé, j'ai fait l'essentiel il me manque plus que la partie relative au module snmp mais j'ai encore des erreurs que j'arrive pas à corriger.
 

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. my $home_stats=".";
  4. my $typecfg="${home_stats}/networkTypes.cfg";
  5. my $itemscfg="${home_stats}/networkTypes.cfg";
  6. my $flic_log="${home_stats}/logs";
  7. my $j;
  8. my (@ips, @name, @types, @communities) = ();
  9. open(ITEMSCFG, $itemscfg) or die "Echec ouverture de $itemscfg : $!";
  10. my $i=0;
  11. foreach my $line ( <ITEMSCFG> )
  12. {
  13.         chomp $line;
  14.         (       $ips[$i],
  15.                 $name[$i],
  16.                 $types[$i],
  17.                 $communities[$i]) = split ':', $line;
  18.         $i++;
  19. }
  20. close(ITEMSCFG);
  21. my @typeName;
  22. my @typeParams;
  23. open(TYPECFG, $typecfg) or die "Echec ouverture de $typecfg : $!";
  24. $i=0;
  25. foreach my $line ( <TYPECFG> )
  26. {
  27. chomp $line;
  28. ( $typeName[$i],
  29.  $typeParams[$i]) = split ':', $line;
  30. $i++;
  31. }
  32. close(TYPECFG);
  33. open ( FLIC_LOG, ">> $flic_log" ) or die "Echec ouverture de $flic_log : $!";
  34. foreach $i (0..scalar (@ips))
  35. {
  36. print "${ips[$i]}";
  37. printf "flic_reseau_${ips[$i]}:";
  38. my $params ="";
  39. foreach my $t (0..scalar (@typeName))
  40.  { if (${typeName[$t]}=${types[$i]})
  41.   { $params = ${typeParams[$t]};
  42.   }
  43.    $t++;
  44.  }
  45.  
  46.  my $id;
  47.  my $snmpName;
  48.  my $desc;
  49.  if ($params != "" )
  50.   {
  51.       my $ifs = "\";
  52.  
  53.    foreach $j (0..scalar (@typeParams))
  54.    {  if ($j>0)
  55.     { printf ";";
  56.     }
  57.    chomp ${params};
  58.    ( $id,
  59.     $snmpName,
  60.     $desc) = split ',' , ${params};
  61.     print "$id : $desc => getsnmp($snmpName)";
  62. #--------------------------------------------------------------------------------------
  63. #module Perl Snmp : Mib compiler
  64. #--------------------------------------------------------------------------------------
  65.    $j++;
  66.    }
  67.   }
  68. $i++;
  69. }


 
message d'erreur :

Citation :


Scalar found where operator expected at ./getStats2.pl line 93, near "print "$id"
  (Might be a runaway multi-line "" string starting on line 85)
        (Do you need to predeclare print?)
syntax error at ./getStats2.pl line 93, near "print "$id "
String found where operator expected at ./getStats2.pl line 93, at end of line
        (Missing semicolon on previous line?)
Can't find string terminator '"' anywhere before EOF at ./getStats2.pl line 93.


Message édité par thurfin le 27-06-2005 à 13:33:27

---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 27-06-2005 à 13:39:26    

Indentation de psychopathe, normal que tu aies du mal à t'y retrouver.
Essaie, même pour des tests, d'écrire du code proprement indenté, ça te fait gagner énormément de temps au final.
 
 
Sur ton script, "perl -c" me retourne :
 

Scalar found where operator expected at test.pl line 93, at end of line
  (Might be a runaway multi-line "" string starting on line 85)
        (Missing operator before ?)


 
En fait, le problème vient avant la ligne 85, elle vient de la ligne 79 :

Code :
  1. my $ifs = "\";


 
Il faut s'avoir que '\', en PERL (comme dans beaucoup de choses d'ailleurs), est un caractère d'échappement : le caractère suivant '\' est interprété comme un caractère de contrôle.
Ca te permet par exemple d'insérer des guillemets (car. " ) entre des guillemets :
 

Code :
  1. print "Voici des guillemets : \" \" ";


 
Or donc, si on en revient à notre ligne 79, en PERL ça se traduit ainsi : "définition de la variable $ifs, chaîne de caractères contenant "; (+ tout ce qui suit après, jusqu'à trouver le guillemet fermant !).
 
Pour pouvoir écrire un '\', il faut "l'échapper" avec... le caractère d'échappement : \
 
Ce qui donne :

Code :
  1. my $ifs = "\\";


 
 
 
 
Sinon, une telle erreur se trouve immédiatement avec un éditeur de texte qui surligne la syntaxe du PERL. Ainsi, tout ce qui suivait cette ligne était considéré comme une chaîne de caractères, ça se voit bien quand les lettres sont coloriées comme si elles étaient reconnues comme des chaînes ;)

Reply

Marsh Posté le 27-06-2005 à 13:53:42    

ok merci.
Pour l'éditeur j'ai pas le choix, je suis sur un serveur AIX via une console putty, bref VI obligatoire.
 
Sinon le IFS viens du script korn shell :
IFS=\;
 
Est-ce que dans ce cas là aussi ca correspond à un caractère d'échappement? (ce qui me semblerait logique au final)


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 27-06-2005 à 13:58:52    

thurfin a écrit :

Sinon le IFS viens du script korn shell :
IFS=\;
 
Est-ce que dans ce cas là aussi ca correspond à un caractère d'échappement?


 
Si c'est du ksh, oui en effet, \ est un caractère d'échappement.
 
En effet, ";" est interprété en ksh par "fin de la commande", un peu comme tu pourrais taper :

ls ; cp machin bidule ; echo "3 commandes sur une seule ligne"


 
Donc pour pouvoir mettre ';' dans $IFS, il faut l'échapper, d'où le '\'.
 
Du coup, dans ton script PERL, tu devrais écrire ta ligne 79 comme ceci :
 

my $ifs = ";";

Reply

Marsh Posté le 27-06-2005 à 14:02:52    

ok merci ca m'avance pas mal.


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 28-06-2005 à 14:53:59    

je voudrai mettre dans un tableau (@param) les donneée comprise dans une chaine ($params), les différents champs sont séparés par ";". Comment faire? En fait je vois pas comment arrêter la boucle.


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 28-06-2005 à 14:59:37    

Citation :

je voudrai mettre dans un tableau (@param) les donneée comprise dans une chaine ($params), les différents champs sont séparés par ";".


 
 
Avec split ?
 

my @param = split ';', $params;

Reply

Marsh Posté le 28-06-2005 à 15:01:43    

c'est aussi simple que ca ?


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 28-06-2005 à 15:02:24    

Bienvenue dans PERL. Nous vous attendions.

Reply

Marsh Posté le 28-06-2005 à 15:05:56    

[:aztechxx]


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 29-06-2005 à 14:23:05    

on peut utiliser le caractère '.' comme séparateur avec split ?
Parceque chez moi là ca semble pas marcher :(
 

Code :
  1. @oids = split '.',$snmpName;
  2. #$snmpName = sysName.0



---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 29-06-2005 à 14:34:52    

thurfin a écrit :

on peut utiliser le caractère '.' comme séparateur avec split ?
Parceque chez moi là ca semble pas marcher :(
 

Code :
  1. @oids = split '.',$snmpName;
  2. #$snmpName = sysName.0



 
split ( http://perldoc.perl.org/functions/split.html ) :

split MOTIF, EXPR


 
MOTIF signifie qu'il s'agit d'une expression régulière.
Or dans ces expressions, '.' signifie "n'importe quel caractère".
Pour lui dire de chercher des caractères '.', et non "n'importe quel caractère", il faut échapper avec un '\' :
 

Code :
  1. @oids = split '\.',$snmpName;
  2. #$snmpName = sysName.0

Reply

Marsh Posté le 29-06-2005 à 14:36:39    

merci, je me doutais d'un truc dans le genre, j'étais en train de tester avec / (en fait fallait le mettre dans l'autre sens) [:dawa]


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 29-06-2005 à 15:05:45    

Code :
  1. @oids = split '\.',$snmpName;
  2. foreach my $z ( 0..scalar (@oids) )
  3. {
  4. $oid .= '.';
  5. $oid .= $mib->resolve_oid($oids[$z]);
  6. };


 
j'ai une boucle de trop qui s'execute dans ce bout de code, il en fait 3 au lieu de 2, ca peut venir d'où ?


Message édité par thurfin le 29-06-2005 à 15:06:03

---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 29-06-2005 à 15:28:21    

bizard ca me le fait aussi avec le début du code.
Si j'execute ca:

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use Net::SNMP;
  4. my $home_stats=".";
  5. my $typecfg="${home_stats}/networkTypes.cfg";
  6. my $itemscfg="${home_stats}/networkItems.cfg";
  7. my $flic_log="${home_stats}/logs";
  8. my $j;
  9. my (@ips, @name, @types, @communities) = ();
  10. open(ITEMSCFG, $itemscfg) or die "Echec ouverture de $itemscfg : $!";
  11. my $i=0;
  12. foreach my $line ( <ITEMSCFG> )
  13. {
  14.         chomp $line;
  15.         (       $ips[$i],
  16.                 $name[$i],
  17.                 $types[$i],
  18.                 $communities[$i]) = split ':', $line;
  19.         $i++;
  20. }
  21. close(ITEMSCFG);
  22. my @typeName;
  23. my @typeParams;
  24. open(TYPECFG, $typecfg) or die "Echec ouverture de $typecfg : $!";
  25. $i=0;
  26. foreach my $line ( <TYPECFG> )
  27. {
  28.         chomp $line;
  29.         (       $typeName[$i],
  30.                 $typeParams[$i]) = split ':', $line;
  31.         $i++;
  32. }
  33. close(TYPECFG);
  34. foreach my $i ( 0..scalar (@ips))
  35. {print("ip : $ips[$i]\n" );
  36. };
  37. foreach $i ( 0..scalar (@typeName))
  38. {print ("blablab : $typeName[$i]\n" );
  39. };


 
j'obtiens ca :

Citation :


ip : 172.24.0.201
ip : 172.24.1.1
ip :
type : RP
type : DNS
type :


 
[edit] la ligne vide disparait si on ajoute "-1" aux foreach, mais ca me parait bizard, ca viens de perl ou de mon code ?


Message édité par thurfin le 29-06-2005 à 15:33:56

---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 29-06-2005 à 15:41:27    

en gros tes fichiers doivent terminer par des lignes vide
 
apres tes chomp, ajoute soit
 
next if (! $line);
 
ou une condition
 
if (! $line)
 
qui englobe le reste de ton code

Reply

Marsh Posté le 29-06-2005 à 15:51:12    

euh non mes fichiers ne se terminent pas par une ligne vide.


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le 29-06-2005 à 15:54:27    

thurfin a écrit :

euh non mes fichiers ne se terminent pas par une ligne vide.


 
essaye avec le "next if (! $line)" et dit moi si ca fonctionne  ;)

Reply

Marsh Posté le 29-06-2005 à 16:00:50    

scalar(@oids) retourne la taille du tableau, et toi ce que tu veux c'est l'index du dernier element
 
donc tu peux faire:
 
for my $z (0..(@oids-1)) {...
 
ou
 
for my $z (0..$#oids) {...
 
mais au fond si ton but est de recuperer la valeur du tableau, pourkoi ne fais tu pas directement ca:
 
for my $z (@oids) { ...
 
en Perl, kand on a à la fois besoin de l'index et de la valeur, on aura plus tendance à faire ca:
 

Code :
  1. my $i=-1;
  2. for my $val (@tab) {
  3.    ++$i;
  4.    print "$i $val\n";
  5. }


 
que ca:
 

Code :
  1. for my $i (0..$#tab) {
  2.   print "$i $tab[$i]\n";
  3. }

Reply

Marsh Posté le 29-06-2005 à 16:04:09    

merci, donc en fait c'est normal je suis rassuré.
Je vais laisser tel quel avec (@oid)-1 ca marche bien m^mem si c'est moins propre.


---------------
De Marx j'ai avant tout retenu la notion de capital
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed