2010-08-16 21 views
6

Dans mon script Perl, j'obtiens des chaînes de chemins de fichiers qui peuvent contenir des variables d'environnement, par ex. $FONTS/test.ttf ou $TMP/file.txt.Comment évaluer les variables shell dans une chaîne?

Je veux maintenant ouvrir ces fichiers comme ceci:

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

Comment puis-je développer maintenant les variables d'environnement avant l'appel ouvert, comme par exemple la coquille bash ferait?

+5

vous voulez vraiment utiliser un 3 arg ouvert ici pour éviter une faille de sécurité. – xenoterracide

+1

Pourrait également fournir des liens: http://stackoverflow.com/questions/318789/whats-the-best-way-to-open-and-read-a-file-in-perl http://stackoverflow.com/ questions/1479741/pourquoi-est-trois-argument-ouvre-appelle-avec-lexical-filehandles-a-perl-best-pratique – daxim

Répondre

12

Si les variables environnementales sont définies, vous pouvez utiliser une simple substitution:

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

Neat et succinct - et, comme toujours, le traitement des erreurs va tout gâcher. Plus précisément, si l'une des variables d'environnement référencées n'est pas définie, vous obtiendrez au mieux un chemin inattendu; Vous pouvez également recevoir des avertissements concernant l'accès à des variables non définies depuis Perl. Bien qu'il existe d'autres notations de shell (comme '$ {TMP}'), elles sont rarement utilisées dans des contextes où cela posera problème. –

+0

@Jonathan, le comportement standard de bash est de substituer la chaîne vide à une variable manquante, donc ce code gère cette condition d'erreur de la manière demandée par l'OP. Je suis d'accord sur les notations de shell alternées J'utilise '$ {FOO:?}' Dans les scripts pour forcer bash à lancer des erreurs sur des variables non définies. –

0

Eh bien ce qui suit est beaucoup plus bavard, mais il semble de gérer correctement la fois la syntaxe $FOO et ${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. 

Voici un échantillon analysé ...

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

Dans cette version, les symboles non définis sont remplacer par une chaîne vide, comme la coquille. Mais dans mes applications, je préfère laisser le symbole invalide en place pour qu'il soit plus facile de voir ce qui s'est mal passé. En outre, si vous bousiller votre correspondant de support, le shell vous donnera une erreur "mauvaise substitution", mais ici, nous allons juste retourner la chaîne avec le symbole brisé toujours en place.

0

Désolé mais vous avez une erreur.

pour travailler en Perl avec des variables SHELL, la syntaxe correcte est: $ ENV {variable}

exemple avec une fonction de sortie GCC couleur:

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

Pourquoi ne pas faire ceci:

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