我们在Unix中使用的一些环境变量如下(仅作为示例):
VAR1=variable1
VAR2=variable2
VAR3=variable3
# and so on
现在,我有一个perl脚本(我们称之为test.pl)
,它读取制表符分隔的文本文件(让我们称之为test.txt
)并在单独的数组中以列方式推送它的内容。第一列例如,test.txt
包含以下信息(第一列中的字符串由/
分隔,但我不知道字符串将包含的/
以及环境变量在什么位置出现):
$VAR1/$VAR2/$VAR3
$VAR3/some_string/SOME_OTHER_STRING/and_so_on/$VAR2
$VAR2/$VAR1/some_string/some_string_2/some_string_3/some_string_n/$VAR2
脚本摘录如下:
use strict;
my $input0 = shift or die "must provide test.txt as the argument 0\n";
open(IN0,"<",$input0) || die "Cannot open $input0 for reading: $!";
my @first_column;
while (<IN0>)
{
chomp;
my @cols = split(/\t/);
my $first_col = `eval $cols[0]`; #### but this does not work
# here goes the push stmt to populate the array
### more code here
}
close(IN0);
问题:如何在这种情况下访问环境变量,以便填充数组如下:
$first_column[0] = variable1/vraible2/variable3
$first_column[1] = variable3/some_string/SOME_OTHER_STRING/and_so_on/variable2
$first_column[2] = variable2/variable1/some_string/some_string_2/some_string_3/some_string_n/variable2
答案 0 :(得分:4)
我认为您正在寻找处理配置文件的方法。我为此目的喜欢Config::Std,尽管CPAN上有很多其他人。
以下是一种处理$cols[0]
内容的方法,以明确的方式显示您需要使用的内容:
#!/usr/bin/perl
use strict; use warnings;
# You should not type this. I am assuming the
# environment variables are defined in the environment.
# They are here for testing.
@ENV{qw(VAR1 VAR2 VAR3)} = qw(variable1 variable2 variable3);
while ( my $line = <DATA> ) {
last unless $line =~ /\S/;
chomp $line;
my @components = split qr{/}, $line;
for my $c ( @components ) {
if ( my ($var) = $c =~ m{^\$(\w+)\z} ) {
if ( exists $ENV{$var} ) {
$c = $ENV{$var};
}
}
}
print join('/', @components), "\n";
}
__DATA__
$VAR1/$VAR2/$VAR3
$VAR3/some_string/SOME_OTHER_STRING/and_so_on/$VAR2
$VAR2/$VAR1/some_string/some_string_2/some_string_3/some_string_n/$VAR2
您可以使用split
代替join
代替s///
中的相应值,而不是%ENV
/ __DATA__
。为了说明,我在eval_path
部分放了第二列,它应该代表路径的描述,并将每一行转换为hashref。注意,我将实际替换考虑到了#!/usr/bin/perl
use strict; use warnings;
# You should not type this. I am assuming the
# environment variables are defined in the environment.
# They are here for testing.
@ENV{qw(VAR1 VAR2 VAR3)} = qw(variable1 variable2 variable3);
my @config;
while ( my $config = <DATA> ) {
last unless $config =~ /\S/;
chomp $config;
my @cols = split /\t/, $config;
$cols[0] = eval_path( $cols[0] );
push @config, { $cols[1] => $cols[0] };
}
use YAML;
print Dump \@config;
sub eval_path {
my ($path) = @_;
$path =~ s{\$(\w+)}{ exists $ENV{$1} ? $ENV{$1} : $1 }ge;
return $path;
}
__DATA__
$VAR1/$VAR2/$VAR3 Home sweet home
$VAR3/some_string/SOME_OTHER_STRING/and_so_on/$VAR2 Man oh man
$VAR2/$VAR1/some_string/some_string_2/some_string_3/some_string_n/$VAR2 Can't think of any other witty remarks ;-)
,因此您可以尝试替代方案而不会弄乱主循环:
{{1}}
输出:
--- - Home sweet home: variable1/variable2/variable3 - Man oh man: variable3/some_string/SOME_OTHER_STRING/and_so_on/variable2 - Can't think of any other witty remarks ;-): variable2/variable1/some_string/some_string_2/some_string_3/some_string_n/variable2
答案 1 :(得分:1)
如果你想允许完整的shell扩展,可以选择使用shell为你做扩展,也许是通过echo:
$ cat input $FOO bar ${FOO//cat/dog} $ FOO=cat perl -wpe '$_ = qx"echo $_"' input cat bar dog
如果您不能信任环境变量的内容,则会带来安全风险,因为在字符串上调用qx可能会导致shell调用嵌入在字符串中的命令。因此,此scriptlet将无法在污点模式(-T)下运行。
答案 2 :(得分:1)
我想你只想这样做:
my @cols = map { s/(\$(\w+))/ $ENV{$2} || $1 /ge; $_ } split /\t/;
你在这里做的是在拆分它们之后,你将采用'$'
的每个序列,然后是 word 字符,并检查是否有一个环境变量用于它,否则保持原样。
e
开关允许您执行替换值的代码。 如果您希望任何环境变量值都为'0'
,那么最好使用5.10中的定义或。
my @cols = map { s|(\$(\w+))| $ENV{$2} // $1 |ge; $_ } split /\t/;
(忽略标记。//
是已定义的,或者不是C注释)
答案 3 :(得分:0)
Perl将其环境变量保存在%ENV
中,在您的情况下,您可以像这样更改代码:
my $first_col = $ENV[$cols[0]];