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

I am new to Perl and trying to package some of my earlier programs into a new program as subroutines. I would like to use Getopt::Long to then specify which subroutines to run. So far I have something that looks kind of like this:

GetOptions( "one" => .....sub1().... , "two" => .....sub2()...., "three" => ....sub3().... ); sub sub1 { print "sub one"; } sub sub2{ print "sub two"; } sub sub3 { print "sub three"; }

I guess I could set each option equal to a $scalar like this:

GetOptions( "one" => $three, "two" => $two, "three" => $three );

I could then call the subroutines using simple if statements. However the last few weeks of working with Perl has led me to suspect that Perl programmers, being clever and brilliant people, have a direct way just calling the subroutines without using if statements at all. Could anyone confirm or dispell this suspicion?

Also I read in the Getopt::Long's perldoc that you need to use "Permute" to set a subroutine as default if no argument is passed in the command line. How would I make it so that subroutine sub1 is called when not argument is given in the command line. Could anyone point me towards an example?

Thank you all for your time and attention.

-mox

Replies are listed 'Best First'.
Re: Using Getopt::Long to call subroutines
by jdporter (Paladin) on Oct 22, 2006 at 04:25 UTC

    Despite what imp says, Getopt::Long works brilliantly for this.

    # handle the no-args case: unless ( @ARGV ) { exit sub1(); } GetOptions( one => \&sub1, two => \&sub2, three => \&sub3, );
    We're building the house of the future together.

      Wow, clever, brilliant and simple. That is exactly what I was looking for, Thanks alot!.

      Just to firm up my understanding:

      unless ( @ARGV ) { exit sub1();

      Does this code mean that unless an arguement is found in the command line it will run subroutine sub1 by default?

      Also, I like your slogan.

      Thanks

      -mox
        Does this code mean that unless an arguement is found in the command line it will run subroutine sub1 by default?

        Yes. Just what you asked for.

        Also, I like your slogan.

        Thanks! You can find a bit about the source of my "signature" on my homenode.

        We're building the house of the future together.
        Just to firm up my understanding:
        unless ( @ARGV ) { exit sub1();
        Does this code mean that unless an arguement is found in the command line it will run subroutine sub1 by default?

        Yes, and as per exit's documentation, it will exit from your program with the value returned by sub1 (unless of course you exit earlier from within sub1) which may be what you want or not depending on what it actually does.

      I stand corrected.

      I hadn't used Getopt::Long in that way before, but will in the future - thanks :)

Re: Using Getopt::Long to call subroutines
by imp (Priest) on Oct 22, 2006 at 03:56 UTC
    Reading commandline options with Getopt::Long is a good thing generally, but seems like overkill for your situation. You could simplify things a bit by using a dispatch table instead.
    use strict; use warnings; my %dispatch = ( one => \&sub1, two => \&sub2, three => \&sub3, ); my $arg = shift @ARGV; if (defined $arg && exists $dispatch{$arg}) { $dispatch{$arg}->(); } else { print "Usage: $0 [-command]\n"; print "Available commands:\n"; print " -$_\n" for sort keys %dispatch; } sub sub1 { print "sub one"; } sub sub2{ print "sub two"; } sub sub3 { print "sub three"; }

      thank you for your swift response!

      I think a dispatch table would be very useful for this simple example but in my actual program I am using @ARGV and the empty <> operator to pass data in from exterior files.

      want my command line too look something like this:

      myusername $: perl myprogram.pl -two /mydire/programs/data

      This way I can run selected subroutines on selected files.

      Thanks for your help!


      -mox
        You can still use that method if you like, as by shifting $arg from @ARGV you remove it from the list of files that will be processed by <>. And you could still use the -two syntax if you liked, here's an example:
        use strict; use warnings; my %dispatch = ( one => \&sub1, two => \&sub2, three => \&sub3, ); sub usage { print "Usage: $0 [-command]\n"; print "Available commands:\n"; print " -$_\n" for sort keys %dispatch; exit 1; } my $arg = shift @ARGV; usage() unless defined $arg; usage() unless $arg =~ /^-/; $arg =~ s/^-//; usage() unless exists $dispatch{$arg}; $dispatch{$arg}->(); sub sub1 { print "one: $_" for <>; } sub sub2{ print "two: $_" for <>; } sub sub3 { print "three: $_" for <>; }