2010-08-15 6 views
0

Certaines des variables d'environnement que nous utilisons dans Unix sont comme ci-dessous (juste un exemple):Perl et de l'environnement Variables

VAR1=variable1 
VAR2=variable2 
VAR3=variable3 
# and so on 

Maintenant, j'ai un script Perl (appelons-le test.pl) qui lit une tabulation fichier texte (appelons-le test.txt) et pousse le contenu de celui-ci dans des colonnes séparées.La première colonne de test.txt contient les informations suivantes par exemple (les chaînes dans la première colonne sont délimitées par / mais je ne sais pas comment / une chaîne contiendrait et à quelle position apparaîtrait la variable d'environnement):

$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 

L'extrait du script est comme ci-dessous:

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); 

Question: Comment puis-je accéder à des variables d'environnement dans une telle situation de sorte que le tableau est rempli comme ci-dessous:

$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 
+1

Votre question n'a pas de sens, s'il vous plaît préciser ..... – ennuikiller

+0

je l'ai montré l'entrée d'échantillon et j'ai montré le résultat souhaité. Quoi d'autre dois-je ajouter maintenant? – sachin

+0

Autorisez-vous également les extensions normales de mots tels que $ {VAR1: -foo} ou les expansions complexes (par exemple les bashismes) comme $ {VAR1 // foo/bar}? –

Répondre

4

Je pense que vous cherchez un moyen de traiter les fichiers de configuration. J'aime Config::Std à cet effet bien qu'il y ait beaucoup d'autres sur CPAN.


Voici un moyen de traitement seulement le contenu de $cols[0] pour montrer de manière explicite ce que vous devez faire avec:

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

au lieu du split/join, vous pouvez utiliser s/// pour remplacer les modèles qui ressemblent à des variables avec les valeurs correspondantes dans %ENV. Par exemple, j'ai mis une deuxième colonne dans la section __DATA__ qui est censée représenter une description du chemin, et a retourné chaque ligne dans un hashref. Remarque, je refactorisée la substitution réelle à eval_path de sorte que vous pouvez essayer des alternatives sans déconner avec la boucle principale:

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

Sortie:

--- 
- 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

Je suis d'accord, il suffit d'utiliser un module de configuration plutôt que de réinventer la roue ... IMHO la différence entre un programmeur débutant et un programmeur intermédiaire est le programmeur intermédiaire commence à avoir l'état d'esprit * "il n'y a pas ** mon problème a Je n'ai jamais été rencontré par quelqu'un d'autre avant ... Je parie qu'il existe une bibliothèque qui résout déjà cela pour moi. "* Le débutant avance juste en pensant qu'ils sont dans un territoire inexploré. – Ether

+0

Merci Sinan. C'était très utile – sachin

0

Perl conserve ses variables d'environnement dans %ENV, dans votre cas, vous pouvez changer votre code comme ceci:

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

Je pense que cela ne fonctionnerait pas parce que le nombre exact de $ cols [0] n'est pas disponible dans% ENV. Corrigez-moi si je me trompe. – sachin

+0

@sachin: Oui, il pourrait y avoir une solution plus fonctionnelle et plus élégante utilisant une regex, mais dites-nous s'il vous plaît ce que le 'contenu exact' serait. Pourquoi ne seraient-ils pas disponibles dans '% ENV'? – MvanGeest

+0

@MvanGeest '% ENV' aurait' $ ENV {VAR1} 'etc. Pas' $ ENV {$ VAR1/$ VAR2/$ VAR3} '. –

1

Si vous voulez permettre l'expansion complète shell, une option d'utiliser le shell pour faire l'expansion pour vous, peut-être par écho:

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

Si vous ne pouvez pas faire confiance au contenu de la variable d'environnement, ce qui introduit une sécurité risque, en invoquant qx sur une chaîne, le shell peut invoquer des commandes incorporées dans la chaîne. Par conséquent, ce scriptlet ne fonctionnera pas en mode taint (-T).

1

Je pense que vous voulez juste faire:

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

Qu'est-ce que vous feriez VOICI après que vous les divisez vous prenez chaque séquence de '$' suivie par mot caractères et de vérifier pour voir s'il y avait une variable d'environnement pour la partie mot de celui-ci, sinon laissez-le tel quel.

  • Le commutateur e sur une substitution vous permet d'exécuter du code pour la valeur de remplacement.
  • Si vous attendez un '0' pour toute valeur de variable d'environnement, il est préférable de faire un défini ou, fourni avec 5.10.

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

(Ignorer le balisage. // est une définition ou non un commentaire C)

+0

Vraiment cool de le faire via Regex – sachin

Questions connexes