在我的 perl 脚本中,我想要两个版本的$config
目录:
my $config='$home/client/config';
和
my $config_resolved="$home/client/config";
但我想从中得到$config_resolved
,$config
即这样的:
my $config_resolved=resolve_vars($config);
我怎么能在perl中做这样的事情?
来自Perl FAQ(每个 Perl 程序员都应该至少阅读一次):
(由布赖恩·d·福伊提供)
如果可以避免,请不要这样做,或者如果您可以使用模板系统,例如 Text::Template 或 Template Toolkit,请改为这样做。您甚至可以使用
sprintf
or完成工作printf
:my $string = sprintf 'Say hello to %s and %s', $foo, $bar;
但是,对于我不想提取完整模板系统的一次性简单情况,我将使用一个包含两个 Perl 标量变量的字符串。在这个例子中,我想扩展
$foo
和$bar
到他们的变量值:my $foo = 'Fred'; my $bar = 'Barney'; $string = 'Say hello to $foo and $bar';
我可以做到这一点的一种方法涉及替换运算符和双
/e
标志。第一个在替换端/e
进行评估$1
并将其转换为$foo
. 第二个以它的值/e
开头$foo
并替换它。$foo
,然后变成“Fred”,这就是字符串中剩下的内容:$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'
/e
也会默默地忽略违反严格的,用空字符串替换未定义的变量名。因为我使用了/e
标志(甚至两次!),所以我遇到了与字符串形式的 eval 相同的安全问题。如果 有什么奇怪的东西$foo
,也许像@{[ system "rm -rf /" ]}
,那么我可能会给自己惹上麻烦。为了解决安全问题,我还可以从哈希中提取值,而不是评估变量名。使用单个
/e
,我可以检查哈希以确保该值存在,如果不存在,我可以用标记替换缺失的值,在这种情况下???
表示我错过了一些东西: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;
我用eval
这个。因此,您必须用它们的值替换所有标量(它们的名称)。
$config = 'stringone';
$boo = '$config/any/string';
$boo =~ s/(\$\w+)/eval($1)/eg;
print $boo;
因为您使用 my 将其声明为私有变量,所以您不妨使用/ee修饰符。这可以找到声明在本地范围内的变量:
$boo =~ s/(\$\w+)/$1/eeg;
这是由s///
.
在下面的程序中,第一个/e
计算字符串$1
以获取$home
,而第二个计算$home
获取变量的值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;
}
输出
HOME/client/config