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

I'm trying to let a user pick which hash to get data from and I think I need to dereference a pointer to do this. Maybe what I have so far will explain better.
use strict; use warnings; my %cs101 = ("joe"=> "80" ); print "Choose which hash\n"; chomp (my $input = <STDIN>); #my $whichhash=\%cs101; my $whichhash="$input"; sub hashvalues { while( (my $key, my $value) = each (%$whichhash) ) { print "$key $value\n"; } } &hashvalues;

I want the input to be the hash name- cs101. When I uncomment out the hard coded dereference the output prints as I think it should.

I've tried many variations of ${var} and concatenation to get \% in front of $input.
I've looked at

perldoc -q "pass.*filehandle"

Is that the answer and I just don't get it?

Thank-you.

Replies are listed 'Best First'.
Re: Dereference array via STDIN
by toolic (Bishop) on Oct 11, 2008 at 02:27 UTC
    Rather than trying to input a variable name, perhaps it might be simpler to input a hash key and store your data in a Hash-of-hashes:
    use warnings; use strict; use Data::Dumper; my %hoh = ( cs101 => { joe => 80 }, cs102 => { moe => 90 } ); print "Choose which hash\n"; chomp (my $input = <STDIN>); if (exists $hoh{$input}) { my %hash = %{ $hoh{$input} }; # dereference hash print Dumper(\%hash); } else { print "$input not found\n"; } __END__ Choose which hash cs101 $VAR1 = { 'joe' => 80 };
      Thanks everyone for the replies. I have some reading to do.
Re: Dereference array via STDIN
by clwolfe (Scribe) on Oct 11, 2008 at 04:07 UTC
    What you're trying to do is use a "symbolic reference". Searching on that term will probably help a lot.

    I see two problems here:

    1. First, use strict will prevent you from using symbolic references at all, because they are generally a bad idea. You should probably do as toolic suggested, and use a hash of hashes. That said, to turn off strictness, use no strict 'refs'; within a block.
    2. Second, symbolic references work by looking up the name of a variable in the symbol table. Only global variables live in the symbol table (though many are placed in packages); the other major type of variable in perl is a lexical variable, which does not appear in teh symbol table. You declare lexical variables using teh keyword my. By saying my %cs101 = ..., you've made it a lexical variable, gaurenteeing it will never show up in the symbol table, and a symbolic ref to it will not work. One way to declare global variables is to use the keyword our (this has aliasing affects in a package as well, but that won't affect things here.)
    Here's a working version:
    use strict; use warnings; our %cs101 = ("joe"=> "80" ); print "Choose which hash\n"; chomp (my $input = <STDIN>); #my $whichhash=\%cs101; my $whichhash="$input"; sub hashvalues { no strict 'refs'; while( my ($key, $value) = each (%{$whichhash}) ) { print "$key $value\n"; } } &hashvalues;
    Read perldoc perlref, focusing on the sections for symbolic references.

    --Clinton

Re: Dereference array via STDIN
by Perlbotics (Archbishop) on Oct 11, 2008 at 09:08 UTC

    FWIW, there is another eval trick:

    use strict; use warnings; my %cs101 = ("joe"=> "80" ); print "Choose which hash\n"; chomp (my $input = <STDIN>); #my $whichhash=\%cs101; my $whichhash="$input"; sub hashvalues { while( (my $key, my $value) = each (%$whichhash) ) { print "$key $value\n"; } } die "Illegal hash name: $input\n" unless $input =~ /^\w\w+$/; eval '$whichhash = \%'.$input; die "Input: <$input> is not a hash name: $@\n" if $@; &hashvalues;
    ... however, executing unchecked user input is no good idea. Consider somebody inputs cs101; unlink $0...
    So, the approach suggested by toolic above is more secure and also allows for better user interaction, i.e. by presenting the user a menu list created from the HoH.

    Update (16:05 CEST): From my point of view, when giving an answer to a SoPW-question, the answer should also include a note about possible drawbacks and limitations. Knowing the pros/cons, helps the reader to decide upon the usefulness of the answer(s) under her/his given circumstances.
    Here, unlink $0 is just an example that is not intended to be a useful exploit but as one that should create awareness of a potential drawback. Creating a usefull exploit is left as an exercise for the reader ;-)
    Seriously, one should not rely on the pure assumption, that the program will always be executed under the same privileges of the user and without malicious intend. I've seen scrips that were designed to be used as CLI tools and later wrapped and executed by a webserver, however vulnerable to injection attacks. This might be far away from the OPs intention, but who knows? Maybe, I should have made this explicit earlier...

      Consider somebody inputs cs101; unlink $0...

      Well, unless the script is run with extra priviledges a user cannot do any more harm than he can from the command line. If the user can unlink $0 from the script itself, he can remove the file from the command line as well.

        If the user can unlink $0 from the script itself, he can remove the file from the command line as well.
        not true for setuid scripts for example. that's also the reason why taint mode is on by default in setuid scripts.
        A reply falls below the community's threshold of quality. You may see it by logging in.