Perl和环境变量

时间:2010-08-15 13:54:46

标签: perl

我们在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

4 个答案:

答案 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]];