OVH Cloud OVH Cloud

Test clef hash dans un document en ligne (dans un eval)

4 réponses
Avatar
Yves Martin
Bonjour,

J'ai un warning dont j'aimerai me débarrasser dans un script.

Mon code correspond à ceci: a.pl
- ouvre un fichier FILE
- évaluation de b.pl (qui écrit dans FILE avec un inline document)
- ferme FILE

Et l'exécution lève 15 warnings identiques à l'endroit où j'évalue 'b.pl':
Use of uninitialized value in concatenation (.) or string at (eval 5) line 1.

Après quelques recherches, je constate qu'il s'agit de warning concernant
l'accès à des valeurs $options{"myparam"} non défini dans le document inline.

Pour simplifier, j'ai réalisé un cas test:

#!/usr/bin/perl

use strict;
use warnings;

open(FILE, ">test.txt");

my %options = ("test" => "coucou");
my $exp = "print FILE <<EOF_server;\n$options{\"truc\"}\n$options{\"test\"}\nEOF_server\nreturn 1;";

print "Result " . eval($exp);
print "\nError " . $@ . "\n";

close(FILE);

Evidemment le warning dit "line 1" même si la valeur non initialisée est loin
dans le document en ligne... ce qui n'aide pas pour trouver

Comment éviter ce warning ? C'est à dire tester l'existence de
$options{"truc"} avant de l'inclure dans le document en ligne ?

Merci d'avance pour votre aide
--
Yves Martin

4 réponses

Avatar
Paul Gaborit
À (at) Wed, 25 Jan 2006 15:14:34 +0100,
Yves Martin écrivait (wrote):
Comment éviter ce warning ? C'est à dire tester l'existence de
$options{"truc"} avant de l'inclure dans le document en ligne ?


if (defined $options{truc}) {
...
}

En revanche, il me semble que vous utilisez 'eval' dans une situation
où ce n'est pas adapté...

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>

Avatar
Yves Martin
Paul Gaborit writes:

À (at) Wed, 25 Jan 2006 15:14:34 +0100,
Yves Martin écrivait (wrote):
Comment éviter ce warning ? C'est à dire tester l'existence de
$options{"truc"} avant de l'inclure dans le document en ligne ?


if (defined $options{truc}) {
...
}


Malheureusement dans un document en ligne (<<EOF .... EOF) seul
'$options{truc}' est interprété...

Je cherche une construction équivalente à celle de bash:

${parameter:-word}
Use Default Values. If parameter is unset or null, the expansion of word is
substituted. Otherwise, the value of parameter is substituted.

mais utilisable directement en document en ligne comme

print FILE <<EOF
Mon template de fichier avec mon paramêtre $options{truc}
inclu... Et support d'une valeur par défaut.
EOF

Si $options{truc} n'existe pas, j'aimerai le remplacer par un chaîne vide pour
éviter les warning de concaténation.

En revanche, il me semble que vous utilisez 'eval' dans une situation où ce
n'est pas adapté...


Vu les informations que j'ai fourni ici, je suis d'accord mais dans le
contexte global du script, c'est bien pratique ;)

--
Yves Martin


Avatar
Paul Gaborit
À (at) Wed, 25 Jan 2006 17:55:14 +0100,
Yves Martin écrivait (wrote):
Malheureusement dans un document en ligne (<<EOF .... EOF) seul
'$options{truc}' est interprété...


Parce que vous cherchez à faire faire à l'interpolation ce qu'on fait
habituellement par des mécanismes de 'template'. Il y a de nombreux
modules pour faire cela. L'un des plus puissants est
Template::Toolkit. On peut aussi faire à la main (cf. ci-dessous).

Je cherche une construction équivalente à celle de bash:

${parameter:-word}
Use Default Values. If parameter is unset or null, the expansion
of word is substituted. Otherwise, the value of parameter is
substituted.

mais utilisable directement en document en ligne comme

print FILE <<EOF
Mon template de fichier avec mon paramêtre $options{truc}
inclu... Et support d'une valeur par défaut.
EOF

Si $options{truc} n'existe pas, j'aimerai le remplacer par un
chaîne vide pour éviter les warning de concaténation.


Ce que je vous propose, c'est de faire votre propre mécanisme de
template. Lorsque vous utilisez de "HERE document", je vous conseille
de toujours préciser eplicitement si vous voulez ou non de
l'interpolation (en mettant soit "EOF" soit 'EOF').
Donc le code que je vous propose :

------------------------------------------------------------
my %options = (truc => "ok"); # bidule n'est pas défini !

my $template = << 'EOF';
Mon template de fichier avec mon paramètre --truc--
inclu... et --bidule-- ?
EOF
(my $result = $template) =~ s{--([a-z]+)--}{$options{$1} || "N/A"}ge;
print $result;
------------------------------------------------------------

Lorsqu'on exécute, on obtient :

------------------------------------------------------------
Mon template de fichier avec mon paramètre ok
inclu... et N/A ?
------------------------------------------------------------

J'ai choisi '--' comme délimiteur mais vous pouvez évidemment adpaté
cela à votre situation. Les options non définies sont remplacées par
'N/A' mais vous pouvez mettre la chaîne vide si vous préférez...

En revanche, il me semble que vous utilisez 'eval' dans une situation où ce
n'est pas adapté...


Vu les informations que j'ai fourni ici, je suis d'accord mais dans le
contexte global du script, c'est bien pratique ;)


Ça peut sembler pratique mais dans 99% des cas, c'est inutile,
inefficace *et* risqué...

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>
Perl en français - <http://perl.enstimac.fr/>


Avatar
Yves Martin
Paul Gaborit writes:

Vu les informations que j'ai fourni ici, je suis d'accord mais dans le
contexte global du script, c'est bien pratique ;)


Ça peut sembler pratique mais dans 99% des cas, c'est inutile,
inefficace *et* risqué...


Merci pour les exemples et les conseils... mon problème, c'est que mon
"template" doit pouvoir faire un peu ce qu'il veut: notamment récupérer des
points de mesures par ssh ou snmp pour générer les blocs de service dans un
fichier de configuration Nagios (efficacité et risque n'ont pas être pris en
compte).

En tout cas, je vais implémenter un mécanisme de remplacement comme proposé,
c'est le plus propre.

A bientôt pour une autre question ;)
--
Yves Martin