【问题标题】:Perl and Environment VariablesPerl 和环境变量
【发布时间】:2013-11-12 20:18:13
【问题描述】:

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

【问题讨论】:

  • 你的问题没有意义,请澄清.....
  • 我已经展示了示例输入并且我已经展示了想要的结果。我现在还应该添加什么?
  • 您是否也允许像 ${VAR1:-foo} 这样的单词的正常 shell 扩展或像 ${VAR1//foo/bar} 这样的复杂扩展(即 bashisms)?

标签: perl


【解决方案1】:

我认为您正在寻找一种处理配置文件的方法。为此我喜欢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__ 部分放置了第二列,它应该代表路径的描述,并将每一行转换为一个 hashref。请注意,我将实际替换为eval_path,因此您可以尝试替代方案而不会弄乱主循环:

#!/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 ;-)

输出:

--- - 甜蜜的家:variable1/variable2/variable3 - 伙计哦伙计:variable3/some_string/SOME_OTHER_STRING/and_so_on/variable2 - 想不出任何其他诙谐的话 ;-): variable2/variable1/some_string/some_string_2/some_string_3/some_string_n/variable2

【讨论】:

  • 我同意,只是使用配置模块而不是重新发明轮子......恕我直言,初学者程序员和中级程序员之间的区别是中级程序员开始有心态“有不可能我的问题以前从来没有被其他人遇到过...我敢打赌有一个图书馆已经为我解决了这个问题。” 初学者只是向前迈进,以为他们处于未知领域领土。
  • 谢谢思南。很有帮助
【解决方案2】:

我想你只是想这样做:

my @cols = map { s/(\$(\w+))/ $ENV{$2} || $1 /ge; $_ } split /\t/;

在这里你要做的是在你拆分它们之后,你将获取每个'$' 序列,后跟 word 字符并检查它的单词部分是否有环境变量,否则保持原样。

  • e 替换开关允许您执行替换值的代码。
  • 如果您希望任何环境变量值都有一个'0',最好使用 5.10 中的 defined 或

    my @cols = map { s|(\$(\w+))| $ENV{$2} // $1 |ge; $_ } split /\t/;
    

(忽略标记。// 是定义或,而不是 C 注释)

【讨论】:

    【解决方案3】:

    如果您想允许完整的 shell 扩展,可以选择使用 shell 为您进行扩展,可能通过 echo:

    $猫输入 $FOO 酒吧 ${FOO//猫/狗} $ FOO=cat perl -wpe '$_ = qx"echo $_"' 输入 猫 酒吧 狗

    如果您不能信任环境变量的内容,这会带来安全风险,因为在字符串上调用 qx 可能会导致 shell 调用嵌入在字符串中的命令。因此,此 scriptlet 将不会在污染模式 (-T) 下运行。

    【讨论】:

      【解决方案4】:

      Perl 将其环境变量保存在 %ENV 中,在您的情况下,您可以像这样更改代码:

      my $first_col = $ENV[$cols[0]];
      

      【讨论】:

      • 我认为这行不通,因为 $cols[0] 的确切包含在 %ENV 中不可用。如果我错了,请纠正我。
      • @sachin:是的,使用正则表达式可能会有更实用、更优雅的解决方案,但请告诉我们“确切内容”是什么。为什么不能在%ENV 中使用它们?
      • @MvanGeest %ENV 会有$ENV{VAR1} 等。不是$ENV{$VAR1/$VAR2/$VAR3}
      猜你喜欢
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2011-12-03
      • 1970-01-01
      • 2015-09-16
      • 2019-08-21
      • 2014-07-03
      相关资源
      最近更新 更多