2010-08-16 10 views
6

Nel mio script Perl ottengo stringhe di percorsi di file che possono contenere variabili di ambiente, ad es. $FONTS/test.ttf o $TMP/file.txt.Come valutare le variabili di shell in una stringa?

Ora voglio aprire i file in questo modo:

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

Come posso ora ampliare le variabili di ambiente prima della chiamata aperta, come per esempio farebbe lo shell bash?

+5

si desidera davvero utilizzare un 3 arg aperto qui per evitare una vulnerabilità di sicurezza. – xenoterracide

+1

Potrebbe anche fornire collegamenti: http://stackoverflow.com/questions/318789/whats-the-best-way-to-open-and-read-a-file-in-perl http://stackoverflow.com/ questions/1479741/why-is-three-argument-open-calls-with-lexical-filehandles-a-perl-best-practice – daxim

risposta

12

Se vengono impostate le variabili ambientali, è possibile utilizzare una semplice sostituzione:

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

Neat and succinct - e, come sempre, l'elaborazione degli errori lo rovinerà. In particolare, se una delle variabili di ambiente a cui si fa riferimento non è impostata, si otterrà al meglio un percorso inaspettato; potresti anche ricevere avvertimenti sull'accesso a variabili non definite da Perl. Sebbene ci siano altre notazioni di shell (come '$ {TMP}'), vengono usate raramente in contesti in cui questo sarà un problema. –

+0

@Jonathan, il comportamento standard per bash è sostituire la stringa vuota per una variabile mancante, quindi questo codice gestisce la condizione di errore nel modo in cui l'OP ha richiesto. Sono d'accordo sulle notazioni di shell alternative Io uso '$ {FOO:?}' Un bel po 'negli script per forzare bash a lanciare errori su variabili unset. –

0

Beh, la seguente è molto più verboso, ma sembra gestire correttamente sia la sintassi $FOO e ${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. 

Ecco un esempio di esecuzione ...

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

In questa versione, i simboli non definiti sono sostituire con una stringa vuota, come il guscio. Ma nelle mie app preferisco lasciare il simbolo non valido non valido, rendendo più facile vedere cosa è andato storto. Inoltre, se si sbaglia la corrispondenza della parentesi, la shell corrisponderà a fornendo un errore di "sostituzione errata", ma qui restituiremo la stringa con il simbolo rotto ancora posizionato.

0

scusate ma vi sbagliate.

di lavorare in perl con variabili di shell, la sintassi corretta è: $ ENV {variabile}

esempio con una colorata funzione di uscita GCC:

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

Perché non solo fare questo:

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