Reputation: 11088
In my perl script I want to have both versions of $config
directory:
my $config='$home/client/config';
and
my $config_resolved="$home/client/config";
But I want to get $config_resolved
from $config
, i.e. something like this:
my $config_resolved=resolve_vars($config);
How can I do such thing in perl?
Upvotes: 3
Views: 3432
Reputation: 69224
From the Perl FAQ (which every Perl programmer should read at least once):
How can I expand variables in text strings?
(contributed by brian d foy)
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;
Upvotes: 5
Reputation: 126722
This is most tidily and safely done by the double-eval modifier on s///
.
In the program below, the first /e
evaluates the string $1
to get $home
, while the second evaluates $home
to get the variable's value HOME
.
use strict;
my $home = 'HOME';
my $config = '$home/client/config';
my $config_resolved = resolve_vars($config);
print $config_resolved, "\n";
sub resolve_vars {
(my $str = shift) =~ s/(\$\w+)/$1/eeg;
return $str;
}
output
HOME/client/config
Upvotes: -1
Reputation: 5153
Because you are using my to declare it as private variable, you might as well use a /ee modifier. This can find variables declared to be in local scope:
$boo =~ s/(\$\w+)/$1/eeg;
Upvotes: 1
Reputation: 3682
I use eval
for this.
So, you must replace all scalars (their names) with their values.
$config = 'stringone';
$boo = '$config/any/string';
$boo =~ s/(\$\w+)/eval($1)/eg;
print $boo;
Upvotes: 2