command-line args style flags from a file 
Author Message
 command-line args style flags from a file

Hi all,

I have a script that I would like to control the behavior from the
command-line or a file.  For example, let's say that I want to
compress a file:
myscript.pl -c -f <inputfile> -o <outputfile>

or compress and remove blank lines :
myscript.pl -c -b -f <inputfile> -o<outputfile>

There are a multitude of examples on how to do command-line flags, but
how can I perform a *series* of operations on a single file?

For example, let's say I have file called do_flags.txt.  Inside of
do_flags.txt are the following lines of text:
---------------------------
-c -o <outputfile-A>
-c -b  -o <outputfile-B>
-b  -o <outputfile-C>
--------------------------

To invoke this series of operations:

myscript.pl -f<inputfile> -L do_flags.txt
b
I have code that works for input from the command-line (using
Getopt::Std).  I've even made an attempt at getting the arguments to
work from a file.  Before I post my code (it's currently about 100
lines), is there some module or example existing code that allows
command-line style flags to be read from a file?

Thanks for your help,

kln



Fri, 01 Jul 2005 01:41:31 GMT  
 command-line args style flags from a file

Quote:
> I have a script that I would like to control the behavior from the
> command-line or a file.  For example, let's say that I want to
> compress a file:
> myscript.pl -c -f <inputfile> -o <outputfile>

I'd expect the App::Config hierarchy to be able to handle this,
although given your example file...

use English;


    open CFG, $file;

Quote:
} else {

}

and its great posting code from an editor which {*filter*}rstands perl :)

--
Stephen Patterson http://www.*-*-*.com/ http://www.*-*-*.com/

Linux Counter No: 142831 GPG Public key: 252B8B37        
Last one down the pub's an MCSE



Fri, 01 Jul 2005 01:53:06 GMT  
 command-line args style flags from a file

Quote:

>Hi all,

>I have a script that I would like to control the behavior from the
>command-line or a file.  For example, let's say that I want to
>compress a file:
>myscript.pl -c -f <inputfile> -o <outputfile>

>or compress and remove blank lines :
>myscript.pl -c -b -f <inputfile> -o<outputfile>

>There are a multitude of examples on how to do command-line flags, but
>how can I perform a *series* of operations on a single file?

>For example, let's say I have file called do_flags.txt.  Inside of
>do_flags.txt are the following lines of text:
>---------------------------
>-c -o <outputfile-A>
>-c -b  -o <outputfile-B>
>-b  -o <outputfile-C>
>--------------------------

>To invoke this series of operations:

>myscript.pl -f<inputfile> -L do_flags.txt
>b
>I have code that works for input from the command-line (using
>Getopt::Std).  I've even made an attempt at getting the arguments to
>work from a file.  Before I post my code (it's currently about 100
>lines), is there some module or example existing code that allows
>command-line style flags to be read from a file?

Would something like: [untested and incomplete code]

use Getopt::Std;
use constant options => 'cbf:o:';

getopts(options . 'L:', \my(%cmd_opts));
my $file = delete $cmd_opts{L};
unless($file) {
  process_options(%cmd_opts);

Quote:
}

else {
  open my $CONFIG, "<", $file;
  for my $opts (<$CONFIG>) {

    getopts(options, \my %file_opts);
    my %all_opts = (%cmd_opts, %file_opts);
    process_options(%all_opts);
  }

Quote:
}

be what you're looking for? The basic idea is to add each set of options from
the file to those given on the command line, then process the whole set.

Ben



Fri, 01 Jul 2005 01:54:33 GMT  
 command-line args style flags from a file

Quote:

> is there some module or example existing code that allows
> command-line style flags to be read from a file?


Do plain ol' file input to read the switches, stuff them

eg:


   getopts('co:');
   print $opt_c, "\n";
   print $opt_o, "\n";

--
    Tad McClellan                          SGML consulting

    Fort Worth, Texas



Fri, 01 Jul 2005 02:02:17 GMT  
 command-line args style flags from a file

Quote:

> I have code that works for input from the command-line (using
> Getopt::Std).  I've even made an attempt at getting the arguments to
> work from a file.  Before I post my code (it's currently about 100
> lines), is there some module or example existing code that allows
> command-line style flags to be read from a file?

You can use Getopt::Std for that, too.  Just read the lines from your

  getopts('...F:', \%Options);  # get command line options
  if ($Options{F}) {    # there is a "-F do_flags.txt"
      open (OPTFILE, "<$Options{F}")
        or die "cannot open option file: $!";
      while (<OPTFILE>) {
          my %LocalOptions = %Options; # inherit global options

          getopts(..., \%LocalOptions); # analyze one line of options
          do_something_with_options (\%LocalOptions);
      }
      close OPTFILE;
  } else {
      do_something_with_options (\%Options);
  }

(untested)

Of course, when using this trivial method you won't get the quoting
capabilities of the shell, i.e. your do_flags.txt should not contain
        -c -o "Output File With Blanks.o"
or something like that.

Ciao,
        Harald
--

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
[Sendmail] can do just about anything.  Its main problem is that
it can do just about anything.
                -- Chris Lewis, UNIX Email Software Survey FAQ



Fri, 01 Jul 2005 02:14:51 GMT  
 command-line args style flags from a file

Quote:


> > I have a script that I would like to control the behavior from the
> > command-line or a file.  For example, let's say that I want to
> > compress a file:
> > myscript.pl -c -f <inputfile> -o <outputfile>

> I'd expect the App::Config hierarchy to be able to handle this,
> although given your example file...

> use English;


>     open CFG, $file;

> } else {

> }

> and its great posting code from an editor which {*filter*}rstands perl :)

I'll take a look at App::Config.

Thanks,

kln



Sat, 02 Jul 2005 05:46:39 GMT  
 command-line args style flags from a file

Quote:


> >[snip]
> >For example, let's say I have file called do_flags.txt.  Inside of
> >do_flags.txt are the following lines of text:
> >---------------------------
> >-c -o <outputfile-A>
> >-c -b  -o <outputfile-B>
> >-b  -o <outputfile-C>
> >--------------------------
> >To invoke this series of operations:
> >myscript.pl -f<inputfile> -L do_flags.txt
> >b
> >[snip]

> Would something like: [untested and incomplete code]

> use Getopt::Std;
> use constant options => 'cbf:o:';

> getopts(options . 'L:', \my(%cmd_opts));
> my $file = delete $cmd_opts{L};
> unless($file) {
>   process_options(%cmd_opts);
> }
> else {
>   open my $CONFIG, "<", $file;
>   for my $opts (<$CONFIG>) {

>     getopts(options, \my %file_opts);
>     my %all_opts = (%cmd_opts, %file_opts);
>     process_options(%all_opts);
>   }
> }

> be what you're looking for? The basic idea is to add each set of options from
> the file to those given on the command line, then process the whole set.

Nice....
I'm always learning new syntax, so could you explain a few statements
in your code?
1. Why use constants? 2. Why options . 'L:'? 3. Why do you have to do
(%cmd_opts, %file_opts)?  Any suggestions on how to do a "soft error
trap within the loop (see the unfinished but tested code below)?
Let's suppose there are 10 lines of commands in a file, but line 3 an
8 are incorrectly formatted (use -Y flag).  How can I by pass that
"bad line" and continue processing.

Thanks,

kln
=========== Code Starts Here =========
CMD LINE
bm.pl -L cmdfile.dat
INPUT
==== cmdfile.dat ===
-c -b -o outfileA
-c -o outfileB
-c
==== cmdfile.dat ===
OUTPUT
Filename: cmdfile.dat
b => 1
c => 1
o => outfileA
****************************************
c => 1
o => outfileB
****************************************
c => 1
****************************************
====== CODE ====
use strict;
use Getopt::Std;
use constant options => 'cbf:o:';

getopts(options . 'L:' , \my %cmd_opts) or useage();

#The delete function returns the value that was deleted
my $file = delete $cmd_opts{L};

if (defined ($file)) {print "Filename: $file \n";}

unless($file) {
        process_options(%cmd_opts);

Quote:
} else {

        open (my $CONFIG, "<", $file) or die "Can't open $file $!";
        for my $opts (<$CONFIG>) {

                getopts(options, \my %file_opts); #Need Soft Error Here
                my %all_opts = (%cmd_opts, %file_opts);
                process_options(%all_opts);
                }

Quote:
}

sub process_options{

         #$flag;
        foreach my $flag (sort keys %cmdline) {
                print "$flag => $cmdline{$flag}\n";
        }
        print "*" x40 . "\n";

Quote:
}

sub useage {    
(my $progName = $0) =~ s!.*/!!;
        die <<CMD
useage: $progName [flags] [files]
        [-i filename] REQUIRED
        or
        [-L <LIST of commands file>] REQUIRED
        [-f <fully qualified filname>] REQUIRED
        [-b remove blank lines]
        [-c Compress the file]
        [-o <Output filename>]
CMD

- Show quoted text -

Quote:
}



Sat, 02 Jul 2005 06:06:23 GMT  
 command-line args style flags from a file

Quote:


> > is there some module or example existing code that allows
> > command-line style flags to be read from a file?


> Do plain ol' file input to read the switches, stuff them

> eg:


>    getopts('co:');
>    print $opt_c, "\n";
>    print $opt_o, "\n";

I'm not sure how this works.  If I can get my code to work in this few
lines I really want to know how it works. :-)

Thanks,

kln



Sat, 02 Jul 2005 06:09:17 GMT  
 command-line args style flags from a file

Quote:

> > I have code that works for input from the command-line (using
> > Getopt::Std).  I've even made an attempt at getting the arguments to
> > work from a file.  Before I post my code (it's currently about 100
> > lines), is there some module or example existing code that allows
> > command-line style flags to be read from a file?

> You can use Getopt::Std for that, too.  Just read the lines from your

>   getopts('...F:', \%Options);  # get command line options
>   if ($Options{F}) {    # there is a "-F do_flags.txt"
>       open (OPTFILE, "<$Options{F}")
>         or die "cannot open option file: $!";
>       while (<OPTFILE>) {
>           my %LocalOptions = %Options; # inherit global options

>           getopts(..., \%LocalOptions); # analyze one line of options
>           do_something_with_options (\%LocalOptions);
>       }
>       close OPTFILE;
>   } else {
>    do_something_with_options (\%Options);
>   }

> (untested)

> Of course, when using this trivial method you won't get the quoting
> capabilities of the shell, i.e. your do_flags.txt should not contain
>         -c -o "Output File With Blanks.o"
> or something like that.

I like this too (see the reply to Ben Morrow).  BTW, can you describe
a non trivial method to handle filenames with spaces?  Also, what is
inherit global options?  The following code has been tested.

Thanks,

kln
============= Code =============
(The input and output is the same as the Ben Morrow reply)

use strict;
use Getopt::Std;

        my $optionFlags = 'cbf:o:F:';
        getopts($optionFlags, \my %Options);  # get command line options
        if ($Options{F}) {    # there is a "-F do_flags.txt"
                open (OPTFILE, "<$Options{F}") or
                die "cannot open option file: $!";
      while (<OPTFILE>) {
          my %LocalOptions = %Options;  # inherit global options

          getopts($optionFlags, \%LocalOptions); # analyze one line of
options
          do_something_with_options (\%LocalOptions);
          }
      close (OPTFILE);
  } else {
        do_something_with_options (\%Options);
 }

sub do_something_with_options
{

        foreach my $flag (sort keys %$cmdline) {
                print "$flag => $cmdline->{$flag} \n";
        }
        print "*" x40 . "\n";

- Show quoted text -

Quote:
}



Sat, 02 Jul 2005 06:18:03 GMT  
 command-line args style flags from a file

Quote:


>> eg:


>>    getopts('co:');
>>    print $opt_c, "\n";
>>    print $opt_o, "\n";

> I'm not sure how this works.  

It works just as I wrote it. Copy it, paste it, run it
and see for yourself.



--
    Tad McClellan                          SGML consulting

    Fort Worth, Texas



Sat, 02 Jul 2005 06:24:06 GMT  
 command-line args style flags from a file

Quote:



>> > I have code that works for input from the command-line (using
>> > Getopt::Std).  I've even made an attempt at getting the arguments to
>> > work from a file.
>> You can use Getopt::Std for that, too.  Just read the lines from your


>> Of course, when using this trivial method you won't get the quoting
>> capabilities of the shell, i.e. your do_flags.txt should not contain
>>         -c -o "Output File With Blanks.o"
>> or something like that.
> I like this too (see the reply to Ben Morrow).  BTW, can you describe
> a non trivial method to handle filenames with spaces?  

That is a Question that is Asked Frequently:

   perldoc -q split

      How can I split a [character] delimited string except when
      inside [character]?

Using the module suggested there:

   use Text::ParseWords;

or, even more non-trivially :-) you could do this


Rather too much job security in that second one though,
so use the module instead.

--
    Tad McClellan                          SGML consulting

    Fort Worth, Texas



Sat, 02 Jul 2005 07:08:16 GMT  
 command-line args style flags from a file

Quote:


[lots of snippage]

>> Would something like: [untested and incomplete code]

>> use Getopt::Std;
>> use constant options => 'cbf:o:';

>> getopts(options . 'L:', \my(%cmd_opts));
>> my $file = delete $cmd_opts{L};
>> unless($file) {
>>   process_options(%cmd_opts);
>> }
>> else {
>>   open my $CONFIG, "<", $file;
>>   for my $opts (<$CONFIG>) {

>>     getopts(options, \my %file_opts);

** (see below)

Quote:
>>     my %all_opts = (%cmd_opts, %file_opts);
>>     process_options(%all_opts);
>>   }
>> }

>> be what you're looking for? The basic idea is to add each set of options
>> from
>> the file to those given on the command line, then process the whole set.

>Nice....
>I'm always learning new syntax, so could you explain a few statements
>in your code?

Sure :)

Quote:
>1. Why use constants?

use constants options => 'cbf:o:';
creates a sub called options that just returns the string 'cbf:o:'. It is
declared with a special prototype that means you never need to call it as
options(): the compiler knows it takes no arguments, so won't try to give it
any. It's basically the same as saying
my $options = 'cbf:o:';
and replacing all occurences of options with $options, except that the
optimizer will try and inline the constant at compile time (because it knows
it's always constant).

Quote:
> 2. Why options . 'L:'?

The options string defined at the top contains all the options you want to
allow from out of a file. From the command line, you want an extra option, -L,
to specify a file to read (I presume you don't want to allow -L in a config
file? That could get highly confusing :). So this means that the command-line
options will be processed for 'cbf:o:L:' whereas the options read from the file
will just be processed with 'cbf:o:', but the option list is only specified in
one place (at the top). This is in general a good idea... if things are
supposed to be the same, make sure the computer knows that :)

Quote:
> 3. Why do you have to do
>(%cmd_opts, %file_opts)?

This will take the options specified on the command line (minus -L), and
combine them with the options you just read out of the file. The reason I put
this in was that in your OP you gave the example

Quote:
>> >myscript.pl -f<inputfile> -L do_flags.txt

where (presumably) -f <inputfile> should be added to each set of flags read
from the file before processing.

The way this works (I'm not sure if you understand this or not: sorry if I'm
being patronising :) is that a hash evaluated in list context returns a list
(key, value, key, value, ...) so that list there will have all the keys and all
the values from both hashes. When that is assigned to %all_opts it will
reconstitute them into key/value pairs within the hash.

With them in that order, options from out of the file will override the same
option from the cmd line: if you want it the other way round, reverse them.

Quote:
>  Any suggestions on how to do a "soft error
>trap within the loop (see the unfinished but tested code below)?
>Let's suppose there are 10 lines of commands in a file, but line 3 an
>8 are incorrectly formatted (use -Y flag).  How can I by pass that
>"bad line" and continue processing.

Hmm, this is tricky :)

like a switch, so inserting


  print STDERR "Line $. of $file is invalid\n";
  next;

Quote:
}

where I have put ** above will check for that. ($. is the current line of the
last filehandle accessed: perldoc perlvar).

To die gracefully if the file gives an unknown flag is a little harder, though,
as getopts just warns in that case.... I 'spec the only answer might be to
replace the getopts line with

eval {
  local $SIG{__WARN__} = sub { die shift; };
  getopts(options, \my %file_opts);
  local $" = ", ";

Quote:
}



  handle_error($err);
  next;

Quote:
}

which is kinda complex :)

To go through it:

The eval sets up an exception-trapping block: any calls to die within that
block won't actually stop the program, they will put the message it died with

nothing dies inside the eval.

The $SIG{__WARN__} makes all warnings into die()s, so if getopts warns about
unknown options you will drop straight out of the eval. The local() means that
warnings will go back to being warnings after the eval is over.

The getopts call is as before.

The local $" = ", " makes it so (until the end of the eval) arrays interpolated
into strings will have ", " added between each element. Otherwise you get no
separator at all, which can be confusing.

Then the die will jump out of the eval if there are any args left in the line
read from the file, telling you what they are.



to leave this bit out: I tend to put it in if I'm going to print a message to
an end-user as they don't really want to know where in the script the message
is coming from. OTOH, it can make debugging harder...

handle_error is called, with the error message. You can do what you like in
here (well, really :). It may be better to move the s/// line inside here:
check if $_[0] =~ /Unknown option/ or $_[0] =~ /Extra rubbish/ and if it
doesn't, call warn normally (so you get any other warnings). Then strip the
rubbish and tell the user (or do nothing, or whatever...).

next; will go back to the top of the for() loop to read the next line from the
file.

Ben



Sat, 02 Jul 2005 17:45:52 GMT  
 command-line args style flags from a file

Quote:




> >> > I have code that works for input from the command-line (using
> >> > Getopt::Std).  I've even made an attempt at getting the arguments to
> >> > work from a file.

> >> You can use Getopt::Std for that, too.  Just read the lines from your


> >> Of course, when using this trivial method you won't get the quoting
> >> capabilities of the shell, i.e. your do_flags.txt should not contain
> >>         -c -o "Output File With Blanks.o"
> >> or something like that.

> > I like this too (see the reply to Ben Morrow).  BTW, can you describe
> > a non trivial method to handle filenames with spaces?  

> That is a Question that is Asked Frequently:

>    perldoc -q split

>       How can I split a [character] delimited string except when
>       inside [character]?

> Using the module suggested there:

>    use Text::ParseWords;

> or, even more non-trivially :-) you could do this


> Rather too much job security in that second one though,
> so use the module instead.

I've seen this in the split FAQ before and just by-passed it because I
didn't need it... ummmm, at the time. :-)
Good, I'll give grep and Text::ParseWords a try.

Thanks,

kln



Sat, 02 Jul 2005 19:39:26 GMT  
 command-line args style flags from a file

Quote:



>>   getopts('...F:', \%Options);  # get command line options
>>   if ($Options{F}) {    # there is a "-F do_flags.txt"
>>       open (OPTFILE, "<$Options{F}")
>>         or die "cannot open option file: $!";
>>       while (<OPTFILE>) {
>>           my %LocalOptions = %Options; # inherit global options

>>           getopts(..., \%LocalOptions); # analyze one line of options
>>           do_something_with_options (\%LocalOptions);
>>       }
>>       close OPTFILE;
>>   } else {
>>    do_something_with_options (\%Options);
>>   }

>> (untested)

>> Of course, when using this trivial method you won't get the quoting
>> capabilities of the shell, i.e. your do_flags.txt should not contain
>>         -c -o "Output File With Blanks.o"
>> or something like that.

> I like this too (see the reply to Ben Morrow).  BTW, can you describe
> a non trivial method to handle filenames with spaces?  

Tad gave an answer on that one already.

Quote:
> Also, what is
> inherit global options?

In the while loop, I use a local hash %LocalOptions to parse the options
from OPTFILE, but before I initialize it with the global options, i.e.
those options the script was started with.  Ben does this using
        my %all_opts = (%cmd_opts, %file_opts);
but the result will be the same (options not mentioned in the current
line of OPTFILE but defined in %LocalOptions will retain their value
even after getopts()).  Of course, these %LocalOptions must be
re-initialized on every loop cycle, or it would accumulate all options
from all lines...

Ciao,
        Harald
--

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
"The rule on staying alive as a program manager is to give 'em a number
or give 'em a date, but never give 'em both at once."



Sat, 02 Jul 2005 22:56:20 GMT  
 command-line args style flags from a file

Quote:



> >>   getopts('...F:', \%Options);  # get command line options
> >>   if ($Options{F}) {    # there is a "-F do_flags.txt"
> >>       open (OPTFILE, "<$Options{F}")
> >>         or die "cannot open option file: $!";
> >>       while (<OPTFILE>) {
> >>           my %LocalOptions = %Options; # inherit global options

> >>           getopts(..., \%LocalOptions); # analyze one line of options
> >>           do_something_with_options (\%LocalOptions);
> >>       }
> >>       close OPTFILE;
> >>   } else {
>  do_something_with_options (\%Options);
> >>   }

> >> (untested)

> >> Of course, when using this trivial method you won't get the quoting
> >> capabilities of the shell, i.e. your do_flags.txt should not contain
> >>         -c -o "Output File With Blanks.o"
> >> or something like that.

> > I like this too (see the reply to Ben Morrow).  BTW, can you describe
> > a non trivial method to handle filenames with spaces?  

> Tad gave an answer on that one already.

> > Also, what is
> > inherit global options?

> In the while loop, I use a local hash %LocalOptions to parse the options
> from OPTFILE, but before I initialize it with the global options, i.e.
> those options the script was started with.  Ben does this using
>         my %all_opts = (%cmd_opts, %file_opts);
> but the result will be the same (options not mentioned in the current
> line of OPTFILE but defined in %LocalOptions will retain their value
> even after getopts()).  Of course, these %LocalOptions must be
> re-initialized on every loop cycle, or it would accumulate all options
> from all lines...

I thought that was the intent...

Thanks,

kln



Sun, 03 Jul 2005 04:22:38 GMT  
 
 [ 15 post ] 

 Relevant Pages 

1. perl command line flags

2. Hiding command-line args?

3. Debug .pl Syntax of command line args ?

4. Case-insensitive Command Line Args

5. command line args not working correctly

6. HELP: How to program command line args

7. perl command line args

8. Passing Args to script via web and command line

9. perl command line args

10. Command line args..?

11. Command line args

12. Question: Perl for Windows command line args?

 

 
Powered by phpBB® Forum Software