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

Oh wise perl monks, I am in need of help hopefully for something simple (yet obviously obscure). What I am trying to do is this. Write a script that uses a library with multiple arrays defined. The script parses command line arguments, the first of which is the name of one of the arrays contained in the library. My problem is how to actually be able to use the string recieved to call the corresponding array. I would post a code snippet but honestly what I have come up with so far just complains that I am trying to use a string as a scalar ref while strict refs are in use. This doesn't work for me and I am wondering if there is a way to do this correctly??
<lib contains> @names = ('joe', 'bob', 'sally');
<script contains> my $string = shift; my @array = @{$string};
<command line would be> $ ./testscript names
Resulting in @array containing joe, bob and sally.

Replies are listed 'Best First'.
Re: using input as array name
by kennethk (Abbot) on Oct 13, 2010 at 23:20 UTC
    One of the effects of use strict; is to disable the use of Symbolic references, which is exactly what you are trying to do. In general, using symbolic references are a bad idea - most of the things you would do with a symbolic reference can be done more effectively with a hash (or, in this case, a hash of arrays). Please read Why it's stupid to use a variable as a variable name - this is required reading before getting into this stuff.

    Like I mentioned above, the natural way to do this is usually a hash of arrays (or HoA). This is actually a hash of array references. See perlreftut, perllol, perlref, and/or perldsc. Your code might look like:

    #!/usr/bin/perl use strict; use warnings; my %hoa = (names => ['joe', 'bob', 'sally'] ); print join ", ", @{$hoa{names}};

    If you actually have a good reason to do what you say, you still need to consider the following from Symbolic references:

    Only package variables (globals, even if localized) are visible to symbolic references. Lexical variables (declared with my()) aren't in a symbol table, and thus are invisible to this mechanism.

    This means you cannot declare your @names array with my, but either must declare it with an explicit package or initialize it without strict in place. Something like:

    #!/usr/bin/perl use strict; my $array_name = 'names'; @main::names = ('joe', 'bob', 'sally'); DISABLE_BLOCK: { # localizes disabling strict no strict 'refs'; print join ", ", @{$array_name}; }
      excellent suggestions etc but the tricky bit of the question is how to call this perl script from command line to request this particular HoA (names) or another, e.g. birthdates.
      without coding this myself, I suggest that part of the solution would be to use one of the standard args modules, which provides a nice mechanism to supply and parse zero or more args to perl in any order/combination. anyway, something possibly to consider. the harder bit of not passing symbolic reference can be done by testing the value supplied to the perl script against possible requests in a switch e.g.
      my $request = shift; switch($request) { case 'names' print @names; case 'birthdays' print @birthdays; else print 'unknown request`; }
      and so forth. if as in my example the names and birthdays are parts of a proper record set and related, e.g. person 1 -> birthday 1, then a slightly more elaborate structure can be created with a hash etc.
      in any case, using such switch or even if statements obviates need to use directly the value of one variable as a symbolic link to another variable.
      the hardest line to type correctly is: stty erase ^H
        Excellent suggestion, wonder why I never thought of using a case statement in a perl script.. All of this is academic at point as I disabled the strict refs as per the first suggestion and now my script is working as required/expected. The reason I felt it necessary to do this in the first place is to allow my monitoring system to run external commands against multiple pre-defined hosts in attempts to "self-heal" certain problems. Once again, thank you everyone for your input and suggestions.