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
};
| [reply] [d/l] |
| [reply] |
Thanks everyone for the replies. I have some reading to do.
| [reply] |
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:
- 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.
- 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 | [reply] [d/l] [select] |
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...
| [reply] [d/l] [select] |
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.
| [reply] |
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.
| [reply] |