Perl и переменные среды - PullRequest
       1

Perl и переменные среды

0 голосов
/ 15 августа 2010

Некоторые переменные окружения, которые мы используем в 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 ]

4 голосов
/ 15 августа 2010

Я думаю, вы ищете способ обработки файлов конфигурации. Мне нравится 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, чтобы вы могли попробовать альтернативы, не вмешиваясь в основной цикл:

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

Выход:

---
- 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 голос
/ 15 августа 2010

Я думаю, вы просто хотите сделать это:

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

Что бы вы сделали здесь, после того, как вы разбили их, вы бы взяли каждую последовательность '$', за которой следуют слово символови проверьте, существует ли переменная окружения для части слова, иначе оставьте ее как есть.

  • Переключатель e при замене позволяет выполнить код для значения замены.
  • Если вы ожидаете '0' для любого значения переменной среды, лучше сделать определенный или , который пришел с 5.10.

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

(игнорировать разметку. // - это определенный или не Си-комментарий)

1 голос
/ 15 августа 2010

Если вы хотите разрешить полное расширение оболочки, один вариант использовать оболочку, чтобы выполнить расширение для вас, возможно, через echo:

$ cat input
$FOO
bar
${FOO//cat/dog}
$ FOO=cat perl -wpe '$_ = qx"echo $&#95;"' input
cat
bar
dog

Если вы не можете доверять содержимому переменной среды, это создает угрозу безопасности, так как вызов qx для строки может привести к тому, что оболочка вызовет команды, встроенные в строку. В результате этот скриптлет не будет работать в режиме taint (-T).

0 голосов
/ 15 августа 2010

Perl сохраняет свои переменные окружения в %ENV, в вашем случае вы можете изменить свой код следующим образом:

my $first_col = $ENV[$cols[0]];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...