DeusVult has asked for the wisdom of the Perl Monks concerning the following question:

Alright, let us say that I have a file, let us call it input.txt. This file reads as follows:
This is the time: $variable
Now let us say that I right the following script:
#!/usr/bin/Perl -w use strict; # as always open ( FILE, "input.txt" ) or die ( "input.txt: $!" ); my $variable = localtime; while (<FILE>) { print $_; }
This script is, of course, spectacularly useless. One might think that it would print "This is the time: -insert time here-". One would be wrong. It prints "This is the time: $variable".

Obviously, I could just write the script to say print localtime;, but that isn't what I'm really trying to do. I just need, in general, the ability to interpolate one level deeper. So the question I have for you, O monkish fonts of everlasting wisdom, is this:

How do I convince Perl to evaluate the values of the variables that are contained in a string that I read from a file?

Some people drink from the fountain of knowledge, others just gargle.

Replies are listed 'Best First'.
Re: Digging interpolation deeper
by OeufMayo (Curate) on Feb 06, 2001 at 21:58 UTC
Re: Digging interpolation deeper
by eg (Friar) on Feb 06, 2001 at 21:58 UTC
Re: Digging interpolation deeper
by davorg (Chancellor) on Feb 06, 2001 at 22:01 UTC

    There are already large numbers of templating systems for Perl on the CPAN. Why waste your own time inventing another one?

    But if you insist, you should probably look at the substitution operator, s/// and, particularly, the /e switch.

    --
    <http://www.dave.org.uk>

    "Perl makes the fun jobs fun
    and the boring jobs bearable" - me

Re: Digging interpolation deeper
by jeroenes (Priest) on Feb 06, 2001 at 22:02 UTC
    You could just do a
    while(<>){ eval( 'print "'.$_.'";' ); }
    But that leaves horrible security holes open. Horrible, I say. At home, I have some code that parses text, and tries to interpolate variables, but it was really awful to write. I guess you won't need my code as someone else will give a decent solution shortly.

    Jeroen
    "We are not alone"(FZ)

Re: Digging interpolation deeper
by MeowChow (Vicar) on Feb 06, 2001 at 22:30 UTC
Re: Digging interpolation deeper
by mr.nick (Chaplain) on Feb 06, 2001 at 23:39 UTC
    You might want to consider using a package like HTML::Template. It allows you to place tags and loops into a file for interpolation on the fly. And it's quite safer than eval :).

    For example:

    template.txt

    This is the time: <!-- TMPL_VAR NAME="TIME" -->

    Source:

    use HTML::Template; my $tmpl=HTML::Template->new(filename => 'template.txt'); $tmpl->param( TIME => scalar localtime(time) ); print $tmpl->output;
    And, in case you didn't realize, it doesn't actually require the source to be HTML as it removes it's own "TMPL_VAR" tags from the template when displaying.
Re: Digging interpolation deeper
by gryphon (Abbot) on Feb 06, 2001 at 23:31 UTC

    Greetings DeusVult,

    I'm not sure how security-wise this may be, but I think it's better than running an eval of user-changable data. Give this a try and let me know what you think. I've assumed a few things here, and I've also made @file_contents so you can see some dummy file data.

    #!/usr/bin/perl -w use strict; my @file_contents; $file_contents[0] = 'My name is $name.'; $file_contents[1] = 'I live in the city of $city.'; $file_contents[2] = '$city is in the state of $state.'; my $file_contents = join("\n", @file_contents); my %stuff_to_parse = ( name => 'Gryphon', city => 'Seattle', state => 'Washington' ); foreach (keys %stuff_to_parse) { $file_contents =~ s/\$$_\b/$stuff_to_parse{$_}/g; } @file_contents = split(/\n/, $file_contents); foreach (@file_contents) { print $_, "\n"; }

    Does this help? Also, anyone out there: Can someone tell me if I made any security mistakes here? Also, the \b on the end of the search pattern could be altered to be a little more robust.

    -Gryphon.

Re: Digging interpolation deeper
by MrNobo1024 (Hermit) on Feb 07, 2001 at 05:47 UTC
    You could use a regexp to parse it, like
    s/(\$\w+)\b/$1/gee
Re: Digging interpolation deeper
by azatoth (Curate) on Feb 06, 2001 at 22:01 UTC
    A search for "localtime" gives you some info on the function :
    $now_string = localtime;  # e.g., "Thu Oct 13 04:54:34 1994"

    I suspect you need to open the file for writing ?
    open ( FILE, ">>input.txt" ) or die ( "input.txt: $!" );


    So the main problem i see here is your string "This is the local time :" is not included any where in the code, so how would it know to print "This is the time : $now_string" to the file? Try this :
    my $variable = localtime; my $words = "This is the time : $localtime"; open (FH">>input.txt") or die "$!\n"; while (<FH>) { print FH $words; }
    <font color="#0000ff"<Azatoth a.k.a Captain Whiplash

    Get YOUR PerlMonks Stagename here!
    Want to speak like a Londoner?