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

OK, I am working on taking the CLI for an application we're using enterprise wide for our Ops folks and it's presented an interesting challenge: It takes values of the form: server_admin -u USER -p PASSWORD cmdName=addTargetServer hostname=host123 ipAddress=1.1.1.1 Though there's approximately 15 'cmdNames' with each able to have anywhere from 2-20 paramaters (hostname and ipAddress in this case). This screamed at first to be ideal to setup as hash values of the form:
my %addTargetServer = ( hostName => "", ipAddress => "" ); my %addTargetApplication = (targetServerHostName => $SERVER, targe +tApplicationType => "Generic", targetApplicationName => ""); my %addTargetAccount = ( targetServerHostName => $SERVER, targetAp +plicationName => $addTargetApplication{targetApplicationName}, target +ServerUserName => "", targetServerAccountPassword => "");
using Getopts::Long I defined appropriate --option tags for these and now I want to define which ones were actually defined from the command line:
my $OPTIONS = GetOptions ( 'user=s' => \$USERNAME, 'passwd=s' => \$PASSWORD, 'server=s' => \$SERVER, 'hostname=s' => \$addTargetServer{hostName}, 'ipaddr=s' => \$addTargetServer{ipAddress}, 'apptype=s' => \$addTargetApplication{targetApplicationType}, 'appname=s' => \$addTargetApplication{targetApplicationName}, 'targetuser=s' => \$addTargetAccount{targetServerUserName}, 'targetpasswd=s' => \$addTargetAccount{targetServerAccountPass +word} );
So now I have defined values in the key pair for a given HASh, but I need to know which cmdName (which in this case is the actual name of the HASH I defined i.e. 'addTargetApplication' or somesuch, but I can't for the life of me now figure out how to get the ACTUAL NAME of said hash for passing to the cmdName parameter in the vendors tool? Any ideas welcome...

Replies are listed 'Best First'.
Re: how to get name of hash value itself?
by GrandFather (Saint) on Jan 23, 2007 at 22:15 UTC

    Why not either a hash of hash or array of hash for the commands?

    Use a hash of hash if each command is unique where the command name (eg 'addTargetServer') is the top level key. Use an array of commands if the order is important or there may be multiple commands with the same name. Add a 'cmdName' key to the command hashes in the AoH case.

    Something like the following code may be what you are after. Given the command line -u USER -p PASSWORD cmdName=addTargetServer hostname=host123 ipAddress=1.1.1.1 cmdName=subTargetServer hostname=host321 ipAddress=1.1.1.2, the following:

    use warnings; use strict; use Getopt::Long; use Data::Dump::Streamer; my %options; Getopt::Long::GetOptions (\%options, "u=s", "p=s"); print "Option $_: value %options{$_}\n" for keys %options; my @commands; my $entry; for (@ARGV) { next unless /(\w+)=(.*)/; $entry = \%{$commands[scalar @commands]} if $1 eq 'cmdName'; $entry->{$1} = $2; } print "\n"; for my $command (@commands) { print join "\n", (map {"$_ = $command->{$_}"} sort keys %$command) +, "\n"; }

    prints:

    Option p: value %options{p} Option u: value %options{u} cmdName = addTargetServer hostname = host123 ipAddress = 1.1.1.1 cmdName = subTargetServer hostname = host321 ipAddress = 1.1.1.2

    DWIM is Perl's answer to Gödel
Re: how to get name of hash value itself?
by ikegami (Patriarch) on Jan 23, 2007 at 21:36 UTC

    What if the user provided hostname and apptype? I believe your approach will lead you to dragons.

    I think you should call GetOptions twice. First call GetOptions with pass_through true to get the common parameters (user, passwd, server) and the action type (cmdName). The call GetOptions with the options required for the specified action.

    Update: Here's an untested solution. I opted to not use GetOptions for the second level to avoid having to specify "-". You could use GetOptions instead of get_args if you desire more flexibility.

    # Example usages: # server_admin -u USER -p PASSWD -s SERVER add_server name=NAME ipad +dr=IPADDR # server_admin -u USER -p PASSWD -s SERVER add_app type=TYPE name=NA +ME # server_admin -u USER -p PASSWD -s SERVER add_user name=NAME passwd +=PASSWD use strict; use warnings; use Getopt::Long qw( ); use File::Basename qw( basename ); my ($USERNAME, $PASSWORD, $SERVER); sub usage { my $prog = basename($0); print STDERR @_; print STDERR "usage: $prog ...\n"; print STDERR " $prog -h for more details\n"; exit(1); } sub help { my $prog = basename($0); print @_; # ...[ Provide detailed help to STDOUT. ]... exit(0); } sub get_args { my (@arg_names) = @_; my %args = map { split(/=/, $_, 2 } @ARGV; foreach (@arg_names) { if (not $args{$_}) { usage("Missing arg $_.\n"); } } my @rv = delete @args{@arg_names}; foreach (keys %args) { usage("Unknown arg $_. Accepting " . join(', ', @arg_names) . "\ +n"); } return @rv; } sub add_server { my ($name, $ipaddr) = get_args(qw( name ipaddr )); ... } sub add_app { my ($type, $name) = get_args(qw( type name )); ... } sub add_user { my ($name, $passwd) = get_args(qw( name passwd )); ... } { my %action = ( add_server => \&add_server, add_app => \&add_app, add_user => \&add_user, ); Getopt::Long::Configure(qw( posix_default )); Getopt::Long::GetOptions( 'help|h|?' => \&help, 'user|u=s' => \$USERNAME, 'passwd|p=s' => \$PASSWORD, 'server|s=s' => \$SERVER, ) or usage(); my $action = shift(@ARGV); usage() unless defined $USERNAME and defined $PASSWORD and defined $SERVER and defined $action; my $action = $actions{$action} or usage("Unknown action $action\n"); $action->(); }
Re: how to get name of hash value itself?
by starX (Chaplain) on Jan 23, 2007 at 21:43 UTC
    I think I'm missing something here. As I understand what you have written, the name of the hash would be '%addTargetApplication'. Where are you trying to get the hash name from?
      Exactly, but I want to get in a string variable 'addtargetApplication' - how do I assign the HASH name to a STRING? I can check to see if any key/value pair in a given hash has value to know whether I need to run that given cmdName.
        It sounds like ikegami and GrandFather have some good suggestions for you, but as far as I understand it, perl doesn't have a get_defined_vars() like php does. Based on what I read in this thread it sounds like going with one of the other suggestions here is your best option.