Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

possible to evaluate scalars stored in a string?

by emilford (Friar)
on Dec 13, 2003 at 03:12 UTC ( [id://314461]=perlquestion: print w/replies, xml ) Need Help??

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

I brought this up briefly in the chatterbox and Bart got me started in the right direction. His solution was to store a reference to the variable as the hash value, which worked as he said it, but didn't work as I need it to. I have a hash that I am looking to store function parameters and some text in. Some of the parameters are stored elsewhere in the script as scalars and would need to be evaluated at the time of use. How would I do something like this:
%hash = ( 'command1' => 'command_name -n $var1 -p $var2 +' ) $var1 = 'foo'; $var2 = 'bar'; system ($hash{'command'});
I am looking for a way to have $var1 and $var2 be replaced with their respective values. Is this possible? Another twist, the solution would have to be compatible with Perl versions 4 and up. Why 4? Because that's what my customer uses at the moment. :-| Thanks.

Replies are listed 'Best First'.
Re: possible to evaluate scalars stored in a string?
by pg (Canon) on Dec 13, 2003 at 03:28 UTC

    Something like: (code tested)

    use strict; use warnings; my $var1 ="a.pl"; my %hash = ( "command1" => "type $var1" ); system ($hash{"command1"});

    Update:

    I was thinking of adding this update, and at the same time, I saw the reply from emilford. I like this better:

    use strict; use warnings; my %hash = ( "command1" => "type %s" ); my $var1 ="a.pl"; system(sprintf($hash{"command1"}, $var1));
      I think this only works because $var1 is defined prior to being stored in the hash. My variables could be definied/changed anywhere in the script. I'm looking for a way to have the scalars in the hash replaced with the most current values. Thanks.
Re: possible to evaluate scalars stored in a string?
by Mr. Muskrat (Canon) on Dec 13, 2003 at 03:21 UTC

    I think that you have answered your question for yourself. What do I mean by that?

    "Some of the parameters are stored elsewhere in the script as scalars and would need to be evaluated at the time of use."

    That's what eval is for! It evaluates things at run time. I'm thinking the last line should be: system(eval{$hash{command1}});

    But I did not test it, YMMV, objects in mirror may be closer than they appear, any bit rot caused by using this is to be blamed upon alpha particles and not me.

    Updated the code snippet (eval needed braces and not parentheses). I did test it, but as always: YMMV, objects in mirror may be closer than they appear, any bit rot caused by using this is to be blamed upon alpha particles and not me.

      I still don't think this works. Here's what I have:
      %alerts = ('command1' => 'Command1 = $val1'); $val1 = 'foobar'; print "eval {$alerts{command1}}";
      This prints out "Command1 = ".

        What you need is eval, BUT 'command $foo' is unlikely to be valid perl so the eval will fail. This regex method works because we capture the scalar and perform the required (double) eval (first eval gets you $var out of $1, second gets you 'value' out of $var). You may wish to add more than \w in the capture after the $ for things like $foo->{bar} if you are getting that weird.

        %hash = ( 'command' => 'command_name -n $var1 -p $var2' ); $var1 = 'foo'; $var2 = 'bar'; $command = $hash{'command'}; $command =~ s/(\$\w+)/$1/gee; print $command; # system ($command); __DATA__ command_name -n foo -p bar
        This is almost certainly a bad way to do it BTW.

        cheers

        tachyon

        Now I'm not even sure how I got it working because I didn't keep my snippet. Oh, well. I really like pg's update that uses sprintf.
Re: possible to evaluate scalars stored in a string?
by etcshadow (Priest) on Dec 13, 2003 at 04:41 UTC
    Actually, it may not be obvious and apparent, but what you are really in need of is a closure. That is, at one point in time, you want to create a hash-value which will depend on the values which other variables have *at a later time* when you look to that value. Here's an example:
    %hash = ( # the sub { ... } means that this is a closure (a subroutine refere +nce) command1 => sub { "command_name -n $var1 -p $var2" } ); $var1 = 'foo'; $var2 = 'bar'; # added "->()" because we are dereferencing a subroutine reference... +a closure system ($hash{'command1'}->());
    Who loves closures? This guy.

    ------------
    :Wq
    Not an editor command: Wq
      Actually... I suppose, as a more direct answer to your question... you can do this:
      %hash = ( # note the single-quotes wrapping the double-quotes... # I've defined a character string which is, itself, a valid # perl expression... which can be eval'd later command1 => ' "command_name -n $var1 -p $var2" ' ); $var1 = 'foo'; $var2 = 'bar'; # this is the "later" I promised above, when we eval # the character string which contains the perl expression system (eval $hash{'command1'});
      The difference between this post and the parent post is actually only a very slight difference. This code is still, in essence, defining a subroutine reference, but it is not a closure. A closure implies static scoping, that is: the $var1 and $var2 which are visible at the time the closure is defined will be the $var1 and $var2 which are referenced at the time the code is executed. This example, however, uses dynamic scoping, that is: the $var1 and $var2 which get referenced when the code is executed are whatever variables named $var1 and $var2 are visible to the scope which executes the code. (static scoping=bound to the scope in which it was defined, dynamic scoping=scoped to wherever it is executed, whenever it is executed)

      Anyway, in this very simple example, the two are functionally equivalent, but if you imagine that the hash is defined in a different scope than the value is asked for (=code is executed), then they will behave differently. Without your full code, I couldn't say which is the right one... but the dynamicaly scoped one is closer to the title of your question at least.

      Aside: In college, I learned about dynamic lexical scoping, and thought someone would have to be on crack to use it, let alone implement it in a language. Then I met eval, and my life was forever changed.


      ------------
      :Wq
      Not an editor command: Wq
Re: possible to evaluate scalars stored in a string?
by bsb (Priest) on Dec 22, 2003 at 08:47 UTC
    The interpolation trick is:
    $perl -de1 DB<1> x $a 0 undef DB<2> x $str = ' \$a is $a and \$a*2 is ${\($a*2)} ' 0 ' \\$a is $a and \\$a*2 is ${\\($a*2)} ' DB<3> $a = 3 DB<4> x eval qq{"$str"} 0 ' $a is 3 and $a*2 is 6 ' DB<5> $a = 5 DB<6> x eval qq{"$str"} 0 ' $a is 5 and $a*2 is 10 '
    But think twice before sending the result to system()

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://314461]
Approved by Mr. Muskrat
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-25 23:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found