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

If anyone can point me towards some resources or provide me with an answer to the following I would greatly appreciate. I have this code. The purpose is to take Input either in a text file or an Ip address range. A synopsis of the code in question:
use strict; use Getopt::Long; my $Input_File=0; my $Ip_Range=0; GetOptions('InputFile|i=s' => \$Input_File 'Ip|I=s' => \$Ip_Range); if ($Input_File xor $Ip_Range) { # We have one or other of the input options given in the command line. } else { no valid input print usage. }
My question is : Am I missing a way for Getopt::Long to take care of the conditional I wrote. Some way or requiring an option to be passed or even better if no option is passed for the script to use ARGV[0] as the input file. For example
script.pl i input.txt script.pl I 10.1.1.1-10.1.1.254 script.pl input.txt
should all be valid. With the code above I can resolve the first two. I have been searching for examples and am missing something very obvious I know. I know I can add an elseif to catch the third case but it seems Getopt::Long should handle this and I am misreading it. Thank you Note Updated bad logic in the conditional and missing ; and reminds one self cut and paste don't retype.

Replies are listed 'Best First'.
Re: Getopt::Long Validation
by jeffa (Bishop) on Oct 20, 2003 at 14:57 UTC
    I took some liberties with your variable and command switch names (too wordy!), i also brought Pod::Usage along for the ride. Hope this helps. :)
    use strict; use warnings; use Pod::Usage; use Getopt::Long; our($file,$range,$help); GetOptions( 'file|f=s' => \$file, 'ip|i=s' => \$range, 'help|h' => \$help, ); pod2usage(-verbose=>2) if $help; unless ($file or $range) { $file = shift or pod2usage(-verbose=>1); } if ($file) { open FH, '<', $file or die "can't read $file\n"; chomp($range = <FH>); } print "$range\n"; __END__ =head1 NAME foo.pl - does something with IP range =head1 SYNOPSIS foo.pl [filename] [-file filename] [-ip IPrange] Options: -file -f file to read -ip -i IP range -help -h help message =head1 EXAMPLES Read from file: foo.pl ip.txt foo.pl -f ip.txt foo.pl -file ip.txt Read from STDIN: foo.pl -i 127.0.0.1 foo.pl -ip 127.0.0.1

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      Thank you I can follow this one the best. I did use pod2usage I just stripped it out of the code to trim the code down so it was more readable. But thank you for the logic of this. Thank you everyone for all the replies.

      On the unless statement should that be xor. Because or is validated left to right but if the left expression is true it stops. So if both were true it would still process?

      So this code could accept:

      foo.pl -f ip.txt -i 127.0.0.1
      I am testing the code now but just questioning if my understanding of the logic is correct. I like to process it in my mind before on the screen.

      Update just ran it and it needs to xor to limit it to one of the two input methods.

        Yep, you sure do. I wrote my code such that the file trumps the IP argument. I personally prefer this, after all - why should i care if the user specifies both? I'll just pick one and go - but the xor does do a better job of making those who don't like to RTFM do so. ;)

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
Re: Getopt::Long Validation
by dragonchild (Archbishop) on Oct 20, 2003 at 14:51 UTC
    I'd recommend not allowing the third option. Either you're using Getopt::Long or you're not. Pick which one you're using and go from there.

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    ... strings and arrays will suffice. As they are easily available as native data types in any sane language, ... - blokhead, speaking on evolutionary algorithms

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

Re: Getopt::Long Validation
by BrowserUk (Patriarch) on Oct 20, 2003 at 15:44 UTC

    This wouldn't satisfy many people's dependancy dependancy, but it does me :).

    #! perl -slw use strict; use vars qw[ $F $FILE $IP $I $H $HELP ]; $IP ||= $I; $FILE ||= $F; $HELP ||= $H; die <<"USAGE" Usage: $0 [-I[P]=n.n.n.n-n.n.n.n] [[-F[ILE]=]file] USAGE if defined $H or not ( $FILE xor $IP or $FILE=shift() ); $IP = do{ local( *ARGV, $/ ) = [$FILE]; <> } unless $IP; print $IP; __END__ P:\test>junk Usage: P:\test\junk.pl8 [-I[P]=n.n.n.n-n.n.n.n] [[-F[ILE]=]fil +e] P:\test>junk -H Usage: P:\test\junk.pl8 [-I[P]=n.n.n.n-n.n.n.n] [[-F[ILE]=]fil +e] P:\test>junk -HELP Usage: P:\test\junk.pl8 [-I[P]=n.n.n.n-n.n.n.n] [[-F[ILE]=]fil +e] P:\test>junk junk.cfg 10.1.1.1-10.1.1.254 P:\test>junk -FILE=junk.cfg 10.1.1.1-10.1.1.254 P:\test>junk -F=junk.cfg 10.1.1.1-10.1.1.254 P:\test>junk -I=10.1.1.1-10.1.1.254 10.1.1.1-10.1.1.254 P:\test>junk -IP=10.1.1.1-10.1.1.254 10.1.1.1-10.1.1.254 P:\test>junk -IP=10.1.1.1-10.1.1.254 -F=junk.cfg Usage: P:\test\junk.pl8 [-I[P]=n.n.n.n-n.n.n.n] [[-F[ILE]=]fil +e]

    And no, I'm not seriously suggesting anyone else should use this, but it does all I need.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    Hooray!

Re: Getopt::Long Validation
by zengargoyle (Deacon) on Oct 20, 2003 at 15:53 UTC

    for the mix, i do it like this...

    my @switch_list_files = (); my @switches = (); GetOptions ( 'list=s' => \@switch_list_files, 'switch=s' => \@switches, ) or die Usage(); @switch_list_files = split(/,/, join(',', @switch_list_files)); @switches = split(/,/, join(',', @switches)); foreach my $file (@switch_list_files) { if (open F, "<$file") { while (<F>) { chomp; push @switches, (split /\s/, $_, 2)[0]; } close F; } else { die "no readum $file: $!\n"; } } die "need some switches!$/" unless @switches; __END__ $ prog -s 192.168.254.1 -s 192.168.254.2,192.168.254.3 -list foo.list +-f bar.list,bat.list $ cat foo.list 192.168.250.1 rest is ignored 192.168.250.2 ditto

    which takes any number of switches in any number of files or specified by any number of options.

Re: Getopt::Long Validation
by Anonymous Monk on Oct 20, 2003 at 17:13 UTC

    Yet another way:

    #!/usr/bin/perl -w use strict; use Getopt::Declare; use vars '$range'; $range = 0; my $opts = Getopt::Declare->new(<<'SPEC') || die <<USAGE; -ip <ip:s> IP range [required] {$range = $ip;} -file <infile:s> get range from file [required] {local @ARGV = $infile;chomp($range=<>)} <infile:s> [ditto] [mutex: -file -ip <infile>] SPEC $0 -file filename | -ip range | filename USAGE print $range,$/;
Re: Getopt::Long Validation
by graff (Chancellor) on Oct 21, 2003 at 06:51 UTC
    Actually, I think I'd prefer not using Getopt::Long (or even Getopt::Std) at all: just expect one argument after the name of the script. If it turns out to be the name of an existing file, read that file; if it's not a file, but it looks like an IP range, treat it as such; otherwise die with a usage message:
    use strict; my $Usage = "$0 lower.ip.addr-upper.ip.addr\n or\n$0 text.file\n"; die $Usage unless @ARGV == 1; my ($iplower, $ipupper); if ( -f $ARGV[0] ) { # treat the arg as a file } elsif ( $ARGV[0] =~ /^((?:\d{1,3}\.){3}\d{1,3})-(\d{1,3}(?:\.\d{1,3}){ +3})$/ ) { ($iplower,$ipupper) = ($1,$2); } else { die "Invalid command-line arg: $ARGV[0]\n\n$Usage"; } ...
    (update: I do not mean to suggest that I'd never use of the Getopt modules -- I do use them often. It's just that for a simple case like this, option flags seem unnecessary: you have to provide one type of arg or the other, and you can't provide both -- these are not really "options", and you don't need a command-line flag to tell them apart.)
      Very true but I might add other options later so wanted the basic logic for doing this with Getopt::Long so I would already be using it if I needed to add oh say verbose which I am thinking of doing. But again good logic to take in. Thank you