Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations wOOdy-Soft on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

A common way to parse cmd line arguments w. switches

Status
Not open for further replies.

zephan

Programmer
Jan 14, 2002
217
A2
Hi All,
I'm pretty sure there is a standard way to deal with switches on command line arguments. What I'm looking for, is a general program bloc where arguments and options are parsed, knowing that options can be passed to program in any order. Eg: if I have got a program called myscript, supporting to options filename (-f) and mode (-m) and one argument arg1, user may call this program by severak ways :
Code:
myscript -fm filename mode arg1 ;
myscript -m -f mode filename arg1 ;
etc...
or at least, user can use options in any order, but cannot used the condensed way (-fm).
Thanks,
Zephan
 
@ARGV is your friend in this case
Code:
 $args=$ARGV[0];
 $file=$ARGV[1];
 if ($file eq "") {
   $file=$args; # no args passed
 } else {
   (@switches)=split(//,$args); #split the args list on characters
   #assume "-" to be $switches[0]
 }
 foreach(@switches) {
   if ($_ eq "f") {
     $fmode=1;
   } elsif ($_ eq "m") {
     $mmode=1;
 ....
   }
 }

Hope that makes sense
--Paul




It's important in life to always strike a happy medium, so if you see someone with a crystal ball, and a smile on their face ...
 
I think it may be easier if you require that your filename come directly after the '-f' and the mode come directly after the '-m'. Then you can loop through your args, using flags to check whether to expect a mode or filename after getting the switch for it. Or you may even be able to use a regex to parse your args.

 
Sorry Paul, it's my mistake, but I could'nt find another word than "switch". The url anr0ld provided speaks about "switches wich takes arguments" and "boolean flags" ; your script processes only boolean flags, and sets variables witch constants.

What I need is a quasi-ready-to-use code to deal with several types of arguments: boolean flags (eg: -f in rm -f filename), options (eg: -l user in crontab -l user), and simple arguments (eg: a, b, c and d in touch a b c d).
I saw on the above url GetOpt can do the job. I wonder also if I can generalize Paul's script to make a pure perl solution.
Thanks all
 
Here's a very basic example of Getopts::Std.

Code:
use Getopt::Std;
use Data::Dumper;

my %options;
getopts("f:s:mt", \%options);

print Dumper \%options;

This will expect (but not require) f, s, m and t command-line switches. If you have warnings turned on, you'll get a warning for any switches not identified.

The 'f' and 's' options (identified with :'s after them) expect a string following them (ex. -f "file1,file2,file3".) The 'm' and 't' options are just flags. Take a look at the Getops-Std documentation for more information.
 
Philote, I dont't necesserely vant to use packages nor reinvente the wheel. I just want the most readable portion of code that do the job and the most practical one. A script like pauls that includes flags and switches whith arguments, etc. is preferable if it is enough compact.
However, I think, thanks to all, I have goy enough elements to write my own.
Regards,
Zephan
 
if you are writing code for your own personal use, feel free to reinvent or hand code. However, if you are working in a business/group environment where your creation might have to be future-maintained by others, you surely should use well documented, standard modules particularly for mundane housekeeping such as argument parsing.

 
arn0ld,

I have a foot in both camps, as I do with Seatbelt law, and how it is applied (more later).

CGI.pm - a very well written module, and very well used. I was just starting to use it about the time of the "cross site scripting vulnerability", and got burned fairly bad, as I had to revisit/handcode a not-small number of scripts, on a few sites.

I still use CGI.pm when it suits, and I handcode when it suits, and I used to wonder about the benefits of modules over 'stupidity' of handrolling code.

I think zephan is entitled to his/her own discretion in the matter. S/He would be well aware of the ramifications rather than wondering whether the dependencies on other modules are worth the risk.

The most important thing is that the deliverable is well documented, in terms of use. And if a future version of Perl changes so radically to require a rewrite, its safe to assume that the modules will need to be maintained as well.

Just my €0.02
--Paul

Seatbelt Law - 2 bad car smashes as a young'un, wore a seatbelt in one, saved my life, other time I WOULD'VE DROWNED... Now statiscally, seat belts save lives ... I would've been a statistic ...



It's important in life to always strike a happy medium, so if you see someone with a crystal ball, and a smile on their face ...
 
it is my opinion that zephan should use standard modules for standard tasks even if that reduces the fun of coding.

If you had to compute sine(x), would you chose to program it as an "infinite series" computation because the library sin() function might 1 day be found to have a bug?

CGI.PM is a concise, powerful implementation tool. I was able to create CGI scripts well before I had an in depth knowledge of HTML. In fact, I used it as a learning tool by dumping the HTML to the terminal or viewing it from the browser. If I would use only guaranteed "0 bug" software packages, I might still be coding in octal.
 
arn0ld,

I'm not denying you your opinion, simply stating that zephan is also entitled to his/hers. I think your point is made, and zephans'.

This is more a philosophy vs. practical question, and talking about it here won't change zephan's mind, until such time as zephan decides to do so.

As for the Sine function, I'd probably just use a table lookup, combined with a subtraction routine, because the problem with "inifinte series" is that you can never really get the deltas that small, to compute efficiently, how small is small, and it's still only an approximation.
B-)
Just kidding, though I very rarely use the Sine function on the calculator since college, let alone on a programming box.

Regards
--Paul

It's important in life to always strike a happy medium, so if you see someone with a crystal ball, and a smile on their face ...
 
while ($OPTION = shift 2ARGV) {
if ($OPTION eq "-f") {
$filename = shift @ARGV;
}
elsif ($OPTION eq "-m") {
$mode = shift @ARGV;
}
else { print "Unknown option"};
}

ex: program.pl -f foo.c -m read

-Nguyen
 
People,
You already know what this guy/gal needs.

Y! just write it for him/her, that way they'd never have to figure it out for themselves ...

I have a problem with evangelism, especialy in the face of adversity ... dunno if anyone's mentioned this recently ... but it has caused wars.

I have an equal problem with undocumented code, and can't understand what 2ARGV reps (unless its a typo, which means SH!T does actually happen)

dot.dot.dot.

G'night

--Paul

It's important in life to always strike a happy medium, so if you see someone with a crystal ball, and a smile on their face ...
 
Hi,
Thanks Paul to defend me (definetly a guy). After seeing the depth it went into, I've decided to be more involved in this thread :)
Basicly, the structure I was asking for is like the below :

Code:
# The script is expecting a list of let's say "words"
while ($word=shift @ARGV)
{
    if ($word=~/^-(\w+)/) 
    {
        # if the word starts by a dash, check each character
        @switches = split //, $1 ;
        while ($current_switch = shift @switches)
        {
            # if it is defined as a boolean, than set it to 1
            if (switch_is_a_boolean($current_switch))
                {
                    $option{$current_switch} = 1 ;
                }
                else 
                {
                    # else retreive its argument
                    $option{$current_switch}= shift @ARGV ;
                }
        }
    }
    else 
    {
        # if its a standalone argument, get it
        push @arguments, $word ;
    }
}

foreach $key (keys %option)
{
    printf "\n$key ---------- $option{$key}" ;
}

foreach $pureargument (@arguments)
{
    printf "\nPure Argument $pureargument" ;
}


sub switch_is_a_boolean
{
# the sub holds a list of characters wich reprensent
# boolean flags rather than options with arguments

    my @list_of_booleans = ('a', 'b', 'c', 'd', 'e');
    my $switch = $_[0] ;
    my $option;
    
    
    my $result = 0 ;
    while ($option=shift @list_of_booleans)
    {
        if ($switch eq $option) 
        { 
            return  1 ; 
            last}
    }
  return "";
}

It's not complete, does'nt deal with switches of more than one character or more than a dash (eg.: --help). Also, I could'nt figure another way to return FALSE than return "". However this works well with simple argument strings.

Code:
perl myscript.pl -mf mode file other -a -b -z 9

Output :
m ---------- mode
f ---------- file
a ---------- 1
z ---------- 9
b ---------- 1
Pure Argument other

Also, there may be a better way to initialize boolean list. Anyway, there are a lot of improvement to make.
Thanks all for your help
 
FMI, did you
perldoc Getopt::Std
perldoc Getopt::Long
as mikevh suggested 3 (three) days ago?

or man Getopt::Std / man Getopt::Long

If so, instead of
does'nt deal with switches of more than one character or more than a dash (eg.: --help)

you would see in Getopt::Long:
this means that options have long names instead of single letters, and are introduced with a double dash "--". Support for bundling of command line options, as was the case with the more traditional single-letter approach, is provided

is this new wheel better?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top