John M. Dlugosz has asked for the wisdom of the Perl Monks concerning the following question:

I normally use Getopt::Long, but this time I want to do something a little different. Instead of pulling out all the flags and options, then going with what's left, I want to process items as I go, one at a time. For example, given command -a foo bar -a- -b baz I want to process the files foo and bar with -a in effect, then it sees -a being turned off and -b turned on, then it processes baz with that current state.

I also want to be able to read options from a file which acts like it was pasted into the command line.

What's a good module/manner to accomplish this?

—John

Replies are listed 'Best First'.
Re: How to parse these command-line options?
by demerphq (Chancellor) on Feb 06, 2003 at 01:10 UTC
    I would still go with Getopt::Long. With the 'require_order' configuration mode it fails on the first item that it encounters that isnt a legal option. Then you can pull off the "nonoption" and do something with it. When done, call Getoptions again. Repeat until @ARGV is empty.
    use Getopt::Long; use Data::Dumper; use strict; my %opts=(a=>0,b=>0,c=>0); sub process_file { my ($opts,$file)=@_; print "Processing $file "; print join ", ", map { "$_ => $opts{$_}" } keys %opts; print "\n"; } Getopt::Long::Configure('require_order'); while (@ARGV) { #print Data::Dumper->Dump([\%opts,\@ARGV],[qw(*opts ARGV)]); GetOptions(\%opts,qw(a! b! c!)); if (@ARGV) { my $file=shift; process_file(\%opts,$file); } } __END__ >perl gopt2.pl file0 -a file1 --noa --b file2 file3 --c file4 --nob fi +le5 Processing file0 a => 0, b => 0, c => 0 Processing file1 a => 1, b => 0, c => 0 Processing file2 a => 0, b => 1, c => 0 Processing file3 a => 0, b => 1, c => 0 Processing file4 a => 0, b => 1, c => 1 Processing file5 a => 0, b => 0, c => 1
    A bit more clever code could avoid having file2 and file3 treated as seperate arguments but as a list. Anyway, hth...

    --- demerphq
    my friends call me, usually because I'm late....

Re: How to parse these command-line options?
by Enlil (Parson) on Feb 05, 2003 at 23:42 UTC
    You could just use Getopt::Long and localize the parameters first set of parameters in @ARGV, get the next set localize @ARGV again. For example:
    use strict; use warnings; use Getopt::Long; my @current_params; my $counter; while ( @current_params = get_next_set() ) { $counter++; print "\nloop $counter:"; local @ARGV = @current_params; my ($alpha,$beta,$gamma); GetOptions ( 'Alpha|a' => \$alpha, 'Beta|b' => \$beta, 'Gamma|g' => \$gamma, ); if ( $alpha ) { print "ALPHA FOUND." } if ( $beta ) { print "BETA FOUND." } if ( $gamma ) { print "GAMMA FOUND." } } ######################## sub get_next_set ######################## { my @temp_set; while ( @ARGV ) { push @temp_set,shift @ARGV; last if $temp_set[$#temp_set] !~ /^-/ and defined $ARGV[0] and $ARGV[0] =~ /^-/; } return @temp_set; } ##get_next_set
    Which produces something like the following:
    E:\>232942.pl -a -b FOO BAR -a -b -g BAR FOO -a -g FOO loop 1:ALPHA FOUND.BETA FOUND. loop 2:ALPHA FOUND.BETA FOUND.GAMMA FOUND. loop 3:ALPHA FOUND.GAMMA FOUND. E:\>
    Anyhow this is the first thing that came to mind when I read your post. And I would like to hear what problems, nuances, I might have overlooked.

    -enlil

Re: How to parse these command-line options?
by BUU (Prior) on Feb 05, 2003 at 22:18 UTC
    Perhaps their a module, but my initial thought would be something fairly simple..
    for(@ARGV) { if/^-/ $mode=$_; elsif($mode){$subTable{$mode}->($_);} else{#error or default mode} }
    This would allow only one mode in effect at a time, so you wouldn't need to bother with 'turning -a off'. (Of course, if you want multiple modes on it becomes much more complicated so i'll just hope theres a module)
      Yea, many different settings, all independant. Also, chainging one-letter switches, handling the values, and all that.
Re: How to parse these command-line options?
by jdporter (Paladin) on Feb 06, 2003 at 14:36 UTC
    Just to clarify what others have said, Yes you can still use Getopt::Long to do what you're trying to do. The Getopt::Long manpage shows the following example:
    my $width = 80; sub process { ... } GetOptions ('width=i' => \$width, '<>' => \&process); When applied to the following command line: arg1 --width=72 arg2 --width=60 arg3 This will call "process("arg1")" while "$width" is "80", "process("arg2")" while "$width" is "72", and "process("arg3")" while "$width" is "60".

    Note also that
    This feature requires configuration option permute...
    Also note that using Getopt::Long, you'll probably want to use its syntax for turning off boolean switches, rather than the one you showed.
    use Getopt::Long; Getopt::Long::Configure( 'permute' ); my( $a, $b ); GetOptions( 'a!' => \$a, 'b!' => \$b, '<>' => \&process, ); sub process { ... } # call with args like -a foo bar -noa -b baz

    jdporter
    The 6th Rule of Perl Club is -- There is no Rule #6.