Reputation: 409
I am working on a script that has some variables which are passed on to a string and then they a printed out. The initial string was only 6 lines I didn't need an external file for it but I now have a new string which can fill over 1000 lines. The new string also has some fields that are to be replaced by variables declared in the script.
The text file has something like:
Hello $name
The code is supposed to have several parts to it.
my $name = 'Foo';
my $content;
open(my $fh, '<', $filename) or die "cannot open file $filename";
{
local $/;
$content = <$fh>;
}
close($fh);
print $content
Expected outcome:
Hello Foo
I am wondering if it's possible to read "Hello $name" from a file but print it as "Hello Foo" since the variable name is declared as Foo.
Upvotes: 3
Views: 1566
Reputation: 491
Simplest way:
my $foo = 'Fred';
my $bar = 'Barney';
my $string = 'Say hello to $foo and $bar';
say eval qq{"$string"}
Upvotes: 1
Reputation: 69274
The correct answer to the question (as you've already seen) is to use a proper templating system instead.
But it's worth noting that this is answered in the Perl FAQ.
How can I expand variables in text strings?
If you can avoid it, don't, or if you can use a templating system, such as Text::Template or Template Toolkit, do that instead. You might even be able to get the job done with
sprintf
orprintf
:my $string = sprintf 'Say hello to %s and %s', $foo, $bar;
However, for the one-off simple case where I don't want to pull out a full templating system, I'll use a string that has two Perl scalar variables in it. In this example, I want to expand
$foo
and$bar
to their variable's values:my $foo = 'Fred'; my $bar = 'Barney'; $string = 'Say hello to $foo and $bar';
One way I can do this involves the substitution operator and a double
/e
flag. The first/e
evaluates$1
on the replacement side and turns it into$foo
. The second/e
starts with$foo
and replaces it with its value.$foo
, then, turns into 'Fred', and that's finally what's left in the string:$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'
The
/e
will also silently ignore violations of strict, replacing undefined variable names with the empty string. Since I'm using the/e
flag (twice even!), I have all of the same security problems I have with eval in its string form. If there's something odd in$foo
, perhaps something like@{[ system "rm -rf /" ]}
, then I could get myself in trouble.To get around the security problem, I could also pull the values from a hash instead of evaluating variable names. Using a single
/e
, I can check the hash to ensure the value exists, and if it doesn't, I can replace the missing value with a marker, in this case???
to signal that I missed something:my $string = 'This has $foo and $bar'; my %Replacements = ( foo => 'Fred', ); # $string =~ s/\$(\w+)/$Replacements{$1}/g; $string =~ s/\$(\w+)/ exists $Replacements{$1} ? $Replacements{$1} : '???' /eg; print $string;
If you're going to be using Perl, then it's really worth your while to spend an afternoon getting to know the FAQ.
Upvotes: 0
Reputation: 385917
So you want your file to be a template. Why not use a proper template language like this one?
use Template qw( );
my %vars = (
name => "Foo",
);
my $tt = Template->new();
$tt->process($qfn, \%vars)
or die($tt->error());
Template:
Hello [% name %]
The output can be captured instead of printed by using ->process
's third arg.
Upvotes: 5