2010-08-16 3 views
6

В моем скрипте Perl я получаю строки путей к файлам, которые могут содержать переменные среды, например. $FONTS/test.ttf или $TMP/file.txt.Как оценить переменные оболочки в строке?

Теперь я хочу, чтобы открыть эти файлы, как это:

open my $handle, "<$filename" or die $!; 

Как я теперь могу расширить переменные окружения перед открытым вызовом, как, например, оболочка bash?

+5

вы действительно хотите использовать 3 arg здесь, чтобы предотвратить уязвимость системы безопасности. – xenoterracide

+1

Можно также указать ссылки: http://stackoverflow.com/questions/318789/whats-the-best-way-to-open-and-read-a-file-in-perl http://stackoverflow.com/ Вопросы/1479741/why-is-three-argument-open-calls-with-lexical-filehandles-a-perl-best-practice – daxim

ответ

12

Если переменные окружения установлены, вы можете использовать простую замену:

$filename =~ s/\$(\w+)/$ENV{$1}/g; 
+2

Уход и сжатие - и, как всегда, обработка ошибок будет испорчена. В частности, если одна из переменных окружения, на которые ссылаются, не установлена, вы, в лучшем случае, получите неожиданный путь; вы также можете получить предупреждения о доступе к неопределенным переменным из Perl. Хотя есть другие обозначения оболочки (например, '$ {TMP}'), они редко используются в контекстах, где это будет проблемой. –

+0

@Jonathan, стандартное поведение для bash заключается в том, чтобы заменить пустую строку на отсутствующую переменную, поэтому этот код обрабатывает это условие ошибки в том, как задает OP. Я согласен с альтернативными обозначениями оболочки. Я использую '$ {FOO:?}' Довольно много в сценариях, чтобы заставить bash выбросить ошибки на неустановленные переменные. –

0

Ну следующее значительно более многословным, но , кажется, правильно обрабатывать как $FOO и ${FOO} синтаксис.

#!/usr/bin/env perl 

use warnings; 
use strict; 

my $filename = $ARGV[0]; 
print(" GIVEN: <$filename>\n"); 
my $expanded = ''; 
my @parts = split(/(\$\w+)|(\${\w+})/, $filename); 
foreach my $seg (@parts) 
    { 
    next if (not defined($seg)); 
    $seg = ($ENV{$1} || '') if ($seg =~ m/\${?(\w+)}?/); 
    $expanded .= $seg; 
    } 

print("IS NOW: <$expanded>\n"); 
print(`echo " ECHO: <$filename>"`); # How the shell did it. 

Вот пример запуска ...

$ ./expand '$TERM ---${TERM}--- ===${FOO}=== $FOO' 
GIVEN: <$TERM ---${TERM}--- ===${FOO}=== $FOO> 
IS NOW: <xterm-color ---xterm-color--- ====== > 
    ECHO: <xterm-color ---xterm-color--- ====== > 
$ 

В этой версии, неопределенные символы заменить пустой строкой, как оболочки. Но в моих приложениях я предпочел бы оставить нераскрытый недействительный символ на месте, чтобы было легче увидеть, что пошло не так. Кроме того, если вы испортили совпадение скобок, оболочка будет даст вам ошибку «плохой замены», но здесь мы просто вернем строку со сломанным символом, все еще на месте.

0

извините, но вы ошибаетесь.

работать в Perl с SHELL переменных, правильный синтаксис: $ ENV {переменная}

пример с цветной НКУ функции выхода:

n=$(tput setaf 0) 
r=$(tput setaf 1) 
g=$(tput setaf 2) 
y=$(tput setaf 3) 
b=$(tput setaf 4) 
m=$(tput setaf 5) 
c=$(tput setaf 6) 
w=$(tput setaf 7) 
N=$(tput setaf 8) 
R=$(tput setaf 9) 
G=$(tput setaf 10) 
Y=$(tput setaf 11) 
B=$(tput setaf 12) 
M=$(tput setaf 13) 
C=$(tput setaf 14) 
W=$(tput setaf 15) 
END=$(tput sgr0) 

colorgcc() 
    { 
    perl -wln -M'Term::ANSIColor' -e ' 
    m/not found$/ and print "$ENV{N}$`$ENV{END}", "$&", "$ENV{END}" 
    or 
    m/found$/ and print "$ENV{N}$`${g}", "$&", "$ENV{END}" 
    or 
    m/yes$/ and print "$ENV{N}$`${g}", "$&", "$ENV{END}" 
    or 
    m/no$/ and print "$ENV{N}$`$ENV{END}", "$&", "$ENV{END}" 
    or 
    m/undefined reference to/i and print "$ENV{r}", "$_", "$ENV{END}" 
    or 
    m/ Error |error:/i and print "$ENV{r}", "$_", "$ENV{END}" 
    or 
    m/ Warning |warning:/i and print "$ENV{y}", "$_", "$ENV{END}" 
    or 
    m/nsinstall/and print "$ENV{c}", "$_", "$ENV{END}" 
    or 
    m/Linking |\.a\b/ and print "$ENV{C}", "$_", "$ENV{END}" 
    or 
    m/Building|gcc|g\+\+|\bCC\b|\bcc\b/ and print "$ENV{N}", "$_", "$ENV{END}" 
    or 
    print; ' 
    } 
2

Почему бы не просто сделать это:

$filename =~ s/\$\{(\w+)\}/$ENV{$1}/g; 
$filename =~ s/\$(\w+)/$ENV{$1}/g; 
Смежные вопросы