Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

getting args without clobbering @ARGV

by bfdi533 (Friar)
on May 11, 2006 at 18:39 UTC ( [id://548791]=perlquestion: print w/replies, xml ) Need Help??

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

I have been using the following code logic for years to process command line args but just came across a case where it was clobbering @ARGV and causing trouble:

my $arg; my $argcount = 0; my $debug = 0; my $infile; while (@ARGV) { $arg = shift @ARGV; if ($arg =~ /-d/) { $debug = 1; } elsif ($argcount == 0) { $infile = $arg; } }

The code in question that I was trying to write was doing a "while (<>)" and trying to read a filename specified on the command line but @ARGV had been "emptied" in my earlier arg script. But, this time I was not explicitly opening the file, rather trying to rely on the <> automatic processing mechanism.

I was wondering if there was a better way to do this to avoid this problem. I know that some options include the getopts stuff but I tried these several years ago and they were very clunky and difficuly to manage, IMHO.

Replies are listed 'Best First'.
Re: getting args without clobbering @ARGV
by revdiablo (Prior) on May 11, 2006 at 18:48 UTC

    I have used Getopt::Long for years, and it doesn't seem very "clunky and difficult to manage", but it could just be me. Here's how I'd do that:

    use Getopt::Long; my $debug = 0; # Optional parameters (removed from @ARGV) GetOptions( 'debug' => \$debug, ); # Positional parameters (left in @ARGV) my ($infile) = @ARGV;

    Update: replaced code ref with simple scalar ref to flag variable

    Update: a few minor points:

    • Getopt::Std certainly is clunky, but Getopt::Long has been included as a standard module since 5.003_07, which was released almost 10 years ago.
    • Getopt::Long will allow shortening of '--debug' down to '-d' by default. That said, it is often preferable to list these more explicitly, as Xaositect has demonstrated.

      Thanks for the suggestion and for the sample code.

      For me I guess "clunky and difficult to manage" comes from the Camel book, pages 452-453 where, using getops you have something like:

      my $debug = 0; getopt('dlv'); if ($opt_d) { $debug = 1; } if ($opt_l) { # do something with arg l } if ($opt_v) { # do something with arg v }

      To me that is not very managable. I can see from your code example and from the CPAN docs for Getopt::Long that this might actually be more workable for me.

      I presume that I have to set some sort of option to be able to use "-d" rather than "-debug"?

        Even better, you can support both with a simple

        GetOptions( 'debug|d' => \$debug, );


        Xaositect - Whitepages.com
Re: getting args without clobbering @ARGV
by davido (Cardinal) on May 11, 2006 at 18:51 UTC

    Clunky as it may be, this is where Getopt::Long excels. With Getopt::Long, the -hyphenated options can be processed, while leaving non-hyphenated (such as filenames) untouched in @ARGV.

    Actually, after you use Getopt::Long a few times I think you'll gain enough familiarity with it that you'll no longer consider it too clunky.


    Dave

Re: getting args without clobbering @ARGV
by GrandFather (Saint) on May 11, 2006 at 18:46 UTC

    Change the while (@ARGV) {$arg = shift @ARGV; to for $arg (@ARGV) {.

    Note though that $arg is aliased to each of the elements of @ARGV in turn so if you change the contents of $arg inside the for loop you will change the contents of @ARGV.


    DWIM is Perl's answer to Gödel

      While I agree with quite about everyone else's opinion that, say, Getopt::Long is very far from being "very clunky and difficuly to manage" and that the OP should better use some Getopt::* module, ++your answer since what is most awkward in his code is the bizarre flow control. Well worth then to point out that the "canonical" way to iterate over an array (or more generally, a list) is a for cycle - unless one has very special needs.

      To this, for the benefit of the OP, I would only add that if he has whatever code that "clobbers" an array, and if this is undesirable, then copying it to another array and working on the latter is certainly possible. Well, it may not be sensible if the starting array is huge, but that can hardly be the case for @ARGV. In this case, as in many others, though it is better not to clobber it in the first place...

Re: getting args without clobbering @ARGV
by ioannis (Abbot) on May 11, 2006 at 19:59 UTC
    While previous posts prop better suggestions, another way is to declare @ARGV with local in a block so it reclaims the old values when it exits the block. As shown bellow, add lines #7, #8, and 19 to the old code:
    my $arg; my $argcount = 0; my $debug = 0; my $infile; #line 7 { #line 8 local @ARGV = @ARGV; while (@ARGV) { $arg = shift @ARGV; if ($arg =~ /-d/) { $debug = 1; } elsif ($argcount == 0) { $infile = $arg; } } #line 19 }
Re: getting args without clobbering @ARGV
by smokemachine (Hermit) on May 11, 2006 at 19:07 UTC
    could be this?
    perl -e 'for(0..$#ARGV){($debug,$infile)=(1,$ARGV[$_+1]) if $ARGV[$_]= +~/-d/}'
Re: getting args without clobbering @ARGV
by BrowserUk (Patriarch) on May 11, 2006 at 20:16 UTC

    For simple scripts, perl's -s option may be all you need. See perlrun for details;


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: getting args without clobbering @ARGV
by graff (Chancellor) on May 12, 2006 at 02:49 UTC
    An idiom I use a lot for quickie ad-hoc scripts with really simple option stuff:
    # really simple: my $debug = ( @ARGV and $ARGV[0] eq '-d' ) ? shift : ''; # or, more in the style of getopt: my %opt; while ( @ARGV and $ARGV[0] =~ /^-([dv])$/ ) { $opt{$1} = 1; shift; }
    But for anything more elaborate, I take the time to recheck the usage for Getopt::Std or Getopt::Long (can't seem to memorize it, but I've gotten better at locating my favorite parts of those man pages) -- it ends up quicker, cleaner and easier to maintain than not using one of those modules.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://548791]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-25 17:56 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found