perl_noobs has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks:

I need to write a file with the name of several variables and its values, here's my code:

#!/usr/bin/perl use warnings; @pizzas=qw ( pizza_margherita $cheese $tomato $mass $USERNAME ); #And 50+ variables... $cheese="cabrales"; $tomato="orlando"; $mass="secret"; $USERNAME=$ENV{USERNAME}; #Loads Windows environment variable USERNAME + value $n = @pizzas; #loads total of array elements open (my $variables, "> C:/temp/variables.txt") or die "Bad Luck..."; for (my $i = 0; $i <= $n; $i++) { print $variables "$pizzas[$i]=$pizzas[$i]\n"; } #I also tried that with the same result #foreach (@pizzas) #{ # print variables "$_=$_\n"; #} close variables;

Gives me this faulty variables.txt output:

pizza_margherita=pizza_margherita $cheese=$cheese $tomato=$tomato $mass=$mass $USERNAME=$USERNAME

Desired variables.txt output:

pizza_margherita=pizza_margherita $cheese=cabrales $tomato=orlando $mass=secret $USERNAME=windowsuser

I have to work with the array variable contents because there are hundreds of arrays with 50+ variables each, I read dozens of posts and tried several methods but it always returns the variable name instead of its contents, how do I may proceed?

Thanks! Regards :)

Replies are listed 'Best First'.
Re: Working with arrays of variables
by jellisii2 (Hermit) on Jun 22, 2015 at 13:18 UTC
Re: Working with arrays of variables
by Anonymous Monk on Jun 22, 2015 at 11:42 UTC

    I strongly recommend you Use strict and warnings, it will lead to cleaner code in general.

    Your data seems to me to be better suited in a hash, e.g.

    use warnings; use strict; my %pizzas = ( pizza_margherita => 'pizza_margherita', cheese => 'cabrales', tomato => 'orlando', mass => 'secret', USERNAME => $ENV{USERNAME}, ); for my $key (keys %pizzas) { print "$key=$pizzas{$key}\n"; } __END__ # Output: USERNAME=foo pizza_margherita=pizza_margherita mass=secret cheese=cabrales tomato=orlando

    To answer your direct question: that is possible with symbolic references or eval, but I wouldn't recommend using either of those because they are advanced techniques that should only be used sparingly and only when you know their use is appropriate, and this doesn't seem like one of those cases, unless you can explain why it is.

Re: Working with arrays of variables
by 1nickt (Canon) on Jun 22, 2015 at 15:33 UTC

    Here's another couple of things to add to the tips you have already received:

    Your "desired" variables.txt output could and should omit the leading '$' from the variable names. There's no reason to have it in there, and you'll have to strip it after you read the file if you want to work easily with the contents. I suggest that your output file should be of the format:

    cheese=cabrales tomato=orlando mass=secret

    etc.

    Since your file is in the format of an *.ini file, you should look into the Config::Tiny module (available on CPAN) which simplifies reading from and writing to *.ini-style files.

    use strict; use warnings; use Config::Tiny; my $ini = Config::Tiny->new; my $outfile = 'pizza.ini'; my %data = ( 'cheese' => 'cabrales', 'tomato' => 'orlando', 'mass' => 'secret', 'USERNAME' => $ENV{'USERNAME'}, ); $ini->{'MySectionName'} = {}; # new section while( my ($key, $val) = each %data ) { $ini->{'MySectionName'}->{ $key } = $val; } $ini->write($outfile, 'utf8');

    This outputs a file containing the following:

    [MySectionName] USERNAME= cheese=cabrales mass=secret tomato=orlando

    Note that the value for USERNAME is blank, because $ENV{'USERNAME'} does not exist on all platforms, e.g. on my Mac laptop. You should make this cross-platform.

    Note that the data are contained in a hash; as others have said, you should convert your data to a hash or hashes before you do anything else. Post a followup question here if you need help with that.

    Also: learn to use Data::Dumper whenever you are developing code with, um, data.

    use strict; use warnings; use feature qw/ say /; use Data::Dumper; my %data = ( 'foo' => 'bar', $cheese => 'cabrales', 'USERNAME' => $ENV{'USERNAME'} ); say Dumper( %data );

    If you run this, you will get an error because $cheese is not pre-declared. That's why you must use strict!!!

    use strict; use warnings; use feature qw/ say /; use Data::Dumper; my %data = ( 'foo' => 'bar', '$cheese' => 'cabrales', 'USERNAME' => $ENV{'USERNAME'} ); say Dumper( \%data );

    If you run this, you will see if the value of $data{'USERNAME'} is undefined ... before you pass it on.

      First of all, thank you all for your time and your help!!!!!!.

      The above code with eval worked for us and we will search more about this method before using it (specially after reading about arbitrary code execution...) or perhaps export the Array contents to a "readable" format (XML, ini, etc.).

      for (my $i=0; $i<$n; $i++) { my $value = $pizzas[$i]; $value = eval $value if $value=~/^\$\w+$/; print $variables "$pizzas[$i]=$value\n"; }

      Perl is new for us, until a few months ago we were working only with VBS but we have been "gifted" with an obsolete Perl project (with "random" surprises as dirty code, few debugged, unuseful functions...).

      Our goal is, by first, that Perl works hand by hand with VBS and gradually migrating platform 100% to VBS (it's a boss decision, not ours, you know... hehe).

      Changing arrays to hashes would be possible, but also would be a long-term "mining" work because we have 300+ different "subprojects", with around 30 .pm each, calling functions from one to anothers (a very funny spiderweb), and one of these 30 .pm is containing the variables array that would be useful for us, those variables in the array could contain Windows environment variables ($ENV{USERNAME}...) (those scripts will only be executed under Windows plattform) or also the absolute path, UNC, strings, numeric, etc. And after changing them to hashes the hard work would be to adapt functions used in those scripts working with this "previous arrays", probably this effort won't be worth because one of these days (or years) the actual "Perl plattform" would be working 100% under VBS.

        Maybe you should suggest to your boss to hire a Perl programmer to migrate the data or the functions to a format you need. It sounds like that may be a lot cheaper as well as an order of magnitude faster, and would allow you and your team to get on with work you know how to do.
Re: Working with arrays of variables
by Anonymous Monk on Jun 22, 2015 at 12:22 UTC

    First, two smaller problems: close variables; should be close $variables; and $i <= $n should be $i < $n.

    If you can, you really should switch to using hashes to store this data. But since you say you've already got "hundreds of arrays with 50+ variables each", here's a way to do what you need, but please note that I would not recommend using this method often. In fact, if you can, maybe your first step should be to convert those hundreds of arrays into a more manageable format first (YAML, JSON, XML, etc.), before continuing to work with them.

    Since eval can execute arbitrary code, which can be a security problem (!), I've added a simple (possibly too simplistic!) check to make sure only things that look like variables are eval-ed.

    for (my $i=0; $i<$n; $i++) { my $value = $pizzas[$i]; $value = eval $value if $value=~/^\$\w+$/; print $variables "$pizzas[$i]=$value\n"; }