[Perl] Retour à Perl - parser une sortie de commande multiligne

Nicolas perl at escwq.fr
Dim 9 Fév 02:41:30 CET 2020


Bonsoir Stéphane,

Merci pour ta proposition !
C'est effectivement sans doute la bonne approche au global, modulo que 
certaines lignes n'ont parfois qu'une seule "clée/valeur" suivant la 
config rencontrée (donc non prévisible).
Il semble que ta regexp "gère ça" mais je n'ai pas encore compris comment :/

Par contre j'aimerai quelques explications (ou une confirmation) sur ta 
regexp stp (j'aime bien comprendre ^_^ ).
/\s*([^:]+):\s+(.*?)(  |\n)/g
/          0) Début de la regexp
\s*        1) Match 0 ou + "espace"
(          2) On commence la sélection => ce sera $1
[^:]+      3) On prend <tous les caractères qui ne sont pas ':'>
):         4) On termine la sélection juste avant le premier ":"
                 A ce stade on a "enlevé tous les espaces de début de 
ligne (1) et ensuite commencé la sélection (2) juste avant de prendre 
<tout ce qui n'est pas ':'> et on termine la sélection juste avant le 
premier ":" rencontré (4), car ":" c'est le séparateur de fin de clée.
\s+        5) Match 0 ou + "espace"
(          6) On commence la sélection => ce sera $2
.*?        7) On prend n'importe quel caractère en mode "non gourmand"
)          8) On termine la sélection
                 A partir d'ici j'ai plus de mal à comprendre car je 
pense que ça doit débuter la sélection de $3, alors qu'on ne l'utilise 
pas après.
(          9) On commence la sélection => ce sera $3
   |\n     10) On prend "2x espace" ou "fin de ligne"
)         11) On termine la sélection
/g        12) Fin de la regex avec utilisation du flag "g" qui va 
matcher répétitivement.

Je pense avoir correctement analysé le contenu mais pas le "but" de la 
regexp "dans son ensemble", en particulier les parties (9) et suivantes.
Je pense que le (10) sert à identifier une "fin de paire cle/valeur" 
avec les 2 espaces consécutifs ou la fin de ligne.
Le flag "g" va permettre de matcher "plusieurs fois" par ligne et donc 
les 2 couples "clé/valeur" par ligne, mais du coup comment perl "fait-il 
le job" en utilisant uniquement $1 et $2 dans le while et que devient $3 ?

En effet, pour une ligne avec 1x "clé/valeur", on va bien avoir :
     $1 = clé
     $2 = valeur
Mais pour une ligne avec 2x "clé/valeur", je m'attendrai à avoir :
     $1 = clé
     $2 = valeur
     $3 = clé
     $4 = valeur

Et là je me rend bien compte que j'ai loupé une subtilité :'(

A noter qu'il faut que je vérifie qu'il y ai toujours au moins "2 
espaces" entre la fin de la "1ere Valeur" et le début de la "2eme clee".
Par contre je dois pouvoir utiliser un lettre "majuscule" (les CLEE sont 
presque exclusivement en majuscule) comme point de repère du début de la 
2eme clée.... faut que je récupère d'avantage de "données brut" pour 
infirmer/confirmer.

@+
Nicolas


Le 09/02/2020 à 00:52, Stéphane Gigandet a écrit :
> Hello Nicolas,
>
> Comme la sortie est toujours de la forme "clé : valeur" (avec 2 paires 
> clés / valeurs sur chaque ligne), le plus simple c'est peut être de 
> parser toutes les clés en un coup, sans découper chaque ligne dans un 
> tableau, avec un truc de ce genre là :
>
> #!/usr/bin/perl -w
>
> use strict;
>
> my $result = `cat result`;
>
> my %values = ();
>
> while ($result =~ /\s*([^:]+):\s+(.*?)(  |\n)/g) {
>         $values{$1} = $2;
> }
>
> foreach my $key (sort keys %values) {
>         print "$key : $values{$key}\n";
> }
>
> Ca donne ça :
>
> ACTIVE PVs : 1
> AUTO ON : yes
> AUTO SYNC : no
> BB POLICY : relocatable
> CRITICAL VG : no
> DISK BLOCK SIZE : 512
> FREE PPs : 21 (2688 megabytes)
> FS SYNC OPTION : no
> HOT SPARE : no
> INFINITE RETRY : no
> LTG size (Dynamic) : 512 kilobyte(s)
> LVs : 28
> MAX LVs : 256
> MAX PPs per PV : 1016
> MAX PPs per VG : 32512
> MAX PVs : 32
> OPEN LVs : 22
> PP SIZE : 128 megabyte(s)
> PV RESTRICTION : none
> QUORUM : 2 (Enabled)
> STALE PPs : 0
> STALE PVs : 0
> TOTAL PPs : 799 (102272 megabytes)
> TOTAL PVs : 1
> USED PPs : 778 (99584 megabytes)
> VG DESCRIPTORS : 2
> VG IDENTIFIER : 00f702be00004c0000000159122168ad
> VG PERMISSION : read/write
> VG STATE : active
> VOLUME GROUP : rootvg
>
> Bon dimanche,
>
> Stéphane
>
> Le 08/02/2020 à 21:56, Nicolas a écrit :
>> Bonsoir,
>>
>> Après de (trop) nombreuses années à ne pas faire d'admin, je remets 
>> (laborieusement) les mains dans le cambouis... et donc dans perl ;o)
>>
>> Je n'ai jamais eu un niveau "gourou" en perl (même il y a 15ans) mais 
>> j'arrive encore à écrire du code qui me donne le résultat attendu.... 
>> alors ça me convient ;o)
>> Mais du coup je vais peut-être avoir une question "bête" concernant 
>> le traitement de la sortie d'une commande.
>>
>> La commande fournit une sortie sur STDOUT que je stocke dans un 
>> tableau via :
>> my @array=split(/\n/,`ma_super_commande_UNIX`) or die "error while 
>> processing command \"ma_super_commande_UNIX\"";
>>
>> Ensuite je fais une boucle pour parcourir le tableau et appliquer la 
>> bonne regexp afin de récupérer les parties "ah-hoc" de chaque ligne 
>> et les stocker dans un hash avec les bonnes clés.
>>
>> La boucle est de la forme :
>> foreach my $scalar (@array)
>> {
>>   if ( $scalar =~ m/VG IDENTIFIER:\s+(\S+)/ )
>>   {
>>     $hash{$stanza}{'VGid'}=$1;
>>   }
>> }
>>
>> En répétant les "if" dans la boucle (un "if" par ligne à traiter avec 
>> la regexp associée) je peux matcher chaque ligne "qui va bien" par 
>> exécution de la commande et ainsi récupérer les 2 valeurs par ligne 
>> qui m'intéressent.
>>
>> A la place du "if" j'ai essayé une notation de la forme :
>>     ($hash{$stanza}{'VGid'}, )=( $scalar =~ m/VG IDENTIFIER:\s+(\S+)/ );
>>
>> Mais ceci a pour seul résultat de bien matcher la bonne ligne dans la 
>> boucle, mais au "tour suivant" de la boucle (ligne suivante stockée 
>> dans @array) alors la valeur est "mise à zéro", ceci sans doute car 
>> du coup la regexp ne match pas ce qui est assez logique puisque ce 
>> n'est plus la bonne ligne.
>> J'ai donc certainement loupé un truc quelque part.....
>> Je peux bien entendu garder ma ribambelle de "if" à l'intérieur de la 
>> boucle mais..... je pense qu'il y a plus simple / plus perl et que je 
>> ne suis pas loin..... :(
>>
>> J'ai mis, un exemple de sortie de commande en fin de mail, je 
>> récupère les 1 ou 2 valeurs par ligne pour stocker la 30aine de 
>> valeurs dans un hash.
>>
>> Bonne soirée,
>> Nicolas
>>
>> VOLUME GROUP:       rootvg                   VG IDENTIFIER: 
>> 00f702be00004c0000000159122168ad
>> VG STATE:           active                   PP SIZE:        128 
>> megabyte(s)
>> VG PERMISSION:      read/write               TOTAL PPs:      799 
>> (102272 megabytes)
>> MAX LVs:            256                      FREE PPs:       21 (2688 
>> megabytes)
>> LVs:                28                       USED PPs:       778 
>> (99584 megabytes)
>> OPEN LVs:           22                       QUORUM:         2 (Enabled)
>> TOTAL PVs:          1                        VG DESCRIPTORS: 2
>> STALE PVs:          0                        STALE PPs:      0
>> ACTIVE PVs:         1                        AUTO ON:        yes
>> MAX PPs per VG:     32512
>> MAX PPs per PV:     1016                     MAX PVs:        32
>> LTG size (Dynamic): 512 kilobyte(s)          AUTO SYNC:      no
>> HOT SPARE:          no                       BB POLICY: relocatable
>> PV RESTRICTION:     none                     INFINITE RETRY: no
>> DISK BLOCK SIZE:    512                      CRITICAL VG:    no
>> FS SYNC OPTION:     no
>>
>>
>> _______________________________________________
>> Perl mailing list
>> Perl at mongueurs.net
>> http://listes.mongueurs.net/mailman/listinfo/perl
>> Attention, les archives sont publiques
>
>
> _______________________________________________
> Perl mailing list
> Perl at mongueurs.net
> http://listes.mongueurs.net/mailman/listinfo/perl
> Attention, les archives sont publiques

-------------- section suivante --------------
Une pièce jointe HTML a été nettoyée...
URL: <http://listes.mongueurs.net/archives/perl/attachments/20200209/c5350ab3/attachment-0001.html>


Plus d'informations sur la liste de diffusion Perl