Re: Request for feedback: Command line options/arguments in NCL

From: Marquardt, Christian (christian.marquardt AT XXXXXX)
Date: Sat Feb 21 2004 - 08:38:43 MST

  • Next message: Dennis Shea: "Re: CLO command line options/arguments in NCL"

    Hi Rick,

    thanks for this question - I do believe that a command line facility
    will greatly enhance the usability of ncl (even more;-))!

    I also apologise beforehand for the length of the email - and it's going
    to be a bit technical.

    To begin with, I believe your option 1 is actually already feasible,
    although with a slightly different syntax. With a script named (say)
    'my_ncl_prog.ncl', you can do something like

       mask=5 smooth=True ncl my_ncl_prog.ncl

    and get the 'arguments' from within my_ncl_prog via

      begin
        auto = getenv("auto")
        smooth = getenv("smooth")
        ...
      end

    at least as strings. The reason is that the shell sets environment
    variables for the program executed (which is ncl) when used in the above
    fashion. If a certain parameter is not set, the ncl variable will be set
    to a missing indicator (or so I understand the output from the print()
    command when I tried it). With this in mind, I wouldn't see a particular
    improvement one gets from option 1.

    What I really would like to have is the possibility to run an ncl script
    like I run any other program from a shell - or say like a ordinary shell
    or perl script. That is, if I have a file 'my_ncl_prog' containing the
    ncl code, I want to be able to do something like (just an example)

      my_ncl_prog --title="My super plot" -p -o myplot.ps input.dat

    In this case, the options would mean (plus a few more I want the script
    to handle):

      -t|--title=... Set the title of the plot to ...
          --ps Generate a PostScript file
          --pdf Generate a pdf file
      -e|--eps Generate an encapsulated PostScript file
      -o|--output=... Name of the output file

    The last argument (without any preciding switch) apparently is the name
    of an input data file. If neither --ps, --pdf or --pdf is given, I would
    want it to show the plot in a (X11) window.

    This requires to things: a) ncl scripts should be runnable from the
    shell, and b) the script gets all the command line arguments given to
    it, and c) there's a way to handle them.

    a) is relatively straightforward: In every Unix shell I know, a
    construct like the following in the first line of the script

      #! /whatever/path/holds/ncl

    will cause the shell to launch the program /whatever/path/holds/ncl and
    pipe the contents of the script into <stdin> of that program. That is
    how we run shell or perl or tk/tcl or python scripts, right? I remember
    that the book "programming Perl" by L. Wall et al. even gives another
    construction that works with perl if the shell is not able to do that.

    The construction does work with ncl (I've tried it), apart from the fact
    ncl complains about the wrong or unknown character # in the first line
    (it still runs the script afterwards). This could easily be remedied by
    allowing # to be a comment character in general, or by letting ncl
    ignore the first line of any script if it starts with a '#' or '#!'.

    I guess that the environment approach to 'arguments', as described
    above, would then work immediately, as in

      auto=5 smooth=True my_ncl_prog

    and with the appropriate getenv() calls within the script itself.

    b) is probably a bit harder. Ordinary shell scripts get all command line
    arguments in $*; the name of the shell script is in $0, the first
    argument in $1, and so on. The user then has to interpret these. Perl
    has its @ARGV array to hold the command line arguments (and $0 to hold
    the script's name), and again lets the user handle the further
    processing.

    In ncl, why can't we get an 'argv' array holding all the command line
    arguments?

    c) Processing the command line arguments really depends on the level of
    sophistication you want your program to have. For a very simple example,
    assume we have a script that is called with two arguments denoting the
    input file and an output file. In a shell or in Perl this is as easy as
    (I use shell notation here)

    #! /bin/sh

      input_file=$1
      output_file=$2

      ...

    With ncl, one could do

    #! /.../ncl

    begin

      input_file = argv(0)
      output_file = argv(1)

      ...

    end

    If you want to use options, I personally favour Perl's Getopt::Long; it
    allows both single and double dashed options, recognises abbreviations,
    and allows to declare if you want options to have arguments (and their
    type). See http://www.perldoc.com/perl5.8.0/lib/Getopt/Long.html for
    more. Perl also has a standard interface to command line options (much
    like the shell's getopts) called Getopt::Std; here, multiple single
    character options can be combined into one (like -abc is the same like
    -a -b -c; we all know that from the standard Unix programs). See
    http://www.perldoc.com/perl5.8.0/lib/Getopt/Std.html for more.

    With the Long version, in Perl I would do something like this (@ at the
    beginning in Perl denotes that it is an array or a list, a $ a scalar
    variable, and the ';' at the end of each line just belongs to Perl):

       @options = ("dryrun|n", "version=i", "number:f");

    and then

       $result = GetOptions(@options);

    The @options list tells Perl that that we allow options --dryrun (which
    is equivalent to -n), --version (which requires an integer argument) and
    --number (which may have an optional floating type / real argument).

    Now, BEFORE the call to GetOptions, all command line arguments (that is,
    the switches, their possible arguments, and any positional command line
    arguments like the file names in the example above) are contained in the
    array @ARGV. AFTER the call, @ARGV only contains positional arguments;
    GetOptions has parsed all arguments and extracted the switches and their
    possible arguments which are allowed according to the @options array. In
    addition, whenever an option has bee set, a variable $opt_<switch> is
    available, which holds the value given to that switch. $result tells you
    if an error occured (e.g., if an unknown option was specified). Or, if,
    for example, the --version switch did not have an integer argument, the
    routine will stop with an error.

    An example of how to use these variables (in perl; perl and C
    afficionados will recognise the '= ? :' syntax)):

       @options = ("dryrun|n", "version=i", "number:f");
       $result = GetOptions(@options);

       if ($result == 0) {
           usage();
           exit;
       }

       $dryrun = defined($opt_dryrun) ? $opt_dryrun : 0
       $version = $opt_version
       $number = defined($opt_number) ? $opt_number : $default_number

    and then later on (assuming that the positional arguments are again
    input and output file names)

       $input_file = $ARGV[0];
       $output_file = $ARGV[1]

    or so. Of course, the $default_* are some default settings. Oh, in perl,
    0 = False.

    Now, I've no idea if that can be put into ncl. But if you already have
    an array containing all command line arguments, you can probably
    relative easily provide an ncl function which is called like (sorry
    about all the typos and syntax errors; I just hope you get the idea)

      allowed_options = (/ "dryrun|n", "version=i", "number:f" /)
      get_options(argv, allowed_options, options)

    where options is a logical variable (False if some wrong / not allowed
    options were given, True otherwise), and put the values into its
    attributes? You could use them like

      if (isatt(options@dryrun)) then
          ...
      endif

      if (isatt(options@number)) then
          number = options@number
      else
          number = default_number
      endif

    and so on.

    Putting that all together - my initial example would look like (I think)

    #! /usr/local/bin/ncl

    begin

      load "..."

      n_args = dimsizes(argv) ; How do I get the number of
                                         ; elements of an array in ncl??

      allowed = (/ "title=s", "ps", "eps", "pdf", "output=s" /)
      get_options(argv, allowed, options)

      if (n_args eq 0 or not options) then
         usage()
         exit
      endif

      if (isatt(options@title)) then
          title = options@title
      else
          title = ""
      endif

      if (isatt(options@output)) then
          outfile = options@output
      else
          outfile = "myplot"
      endif

      if (isatt(options@ps)) then
          gsn_open_wks("ps", outfile)
      else
          if (isatt(options@eps)) then
              gsn_open_wks("eps", outfile)
          else
              if (isatt(options@pdf)) then
                  gsn_open_wks("pdf", outfile)
              else
                  gsn_open_wks("x11", outfile)
              endif
          endif
      endif

      infile = argv(0)

    ; Do the plot etc.

    end

    Just my thoughts. Again, sorry for the length of this email.

      Chris.

    On Thu, 2004-02-19 at 22:56, Rick Grubin wrote:
    > Dear NCL users,
    >
    > The NCL Development Team is considering introducing command line options
    > and arguments into NCL. The Team would appreciate user input before any
    > decisions are made.
    >
    > If you would find this functionality useful, please let us know how
    > you would use it. Specific examples are welcome.
    >
    > Below are two possible methods for implementing command line options
    > and arguments. Would either, or both, meet your needs? Other ideas
    > are welcome.
    >
    > 1. Command line arguments are user defined, and consist of [name=value] pairs
    >
    > Example arguments and usage:
    > mask=5
    > smooth=True
    >
    > ncl mask=5 smooth=True myScript.ncl
    >
    > Within an NCL script, the method for retrieval of specified information
    > from the command line might look something like:
    >
    > begin
    > mask_val = get_ARGS("mask")
    > make_smooth = get_ARGS("smooth")
    > ...
    > end
    >
    > A function like "get_ARGS()" is currently a placeholder function, to
    > illustrate how accessing command line arguments might occur.
    >
    >
    > 2. Command line options are pre-defined, and may take one of two forms:
    > options with single dashes, or options with double dashes.
    >
    > Single dash:
    > -option=value pairs, or simply -option
    >
    > Example options and usage:
    > -f myData.nc
    > -v T
    > -r
    >
    > ncl -f myData.nc -v T -r myScript.ncl
    >
    > Double dash:
    > --option=value pairs, or simply --option
    >
    > Example options and usage:
    > --file=myData.nc
    > --variable=T
    > --version
    >
    > ncl --file=myData.nc --variable=T --version myScript.ncl
    >
    > For information provided via command line options, NCL code might look
    > something like:
    >
    > begin
    > datafile = get_ARGS("file") ; -f myData.nc or --file=myData.nc
    > g = addfile(datafile, "r")
    >
    > tvar = get_ARGS("variable") ; -v T or --variable=T
    > var_to_plot = g->$tvar$
    > ...
    > end
    >
    >
    > Please note that the NCL script name to execute (if one is provided) is
    > always the last argument on the command line, regardless of the method chosen
    > for command line arguments/options. As well, the name of the NCL script
    > to execute would be available to the user within that script.
    >
    > Thank you for your input!
    >
    > The NCL Development Team
    >
    > _______________________________________________
    > ncl-talk mailing list
    > ncl-talk AT ucar.edu
    > http://mailman.ucar.edu/mailman/listinfo/ncl-talk

    -- 
    Dr Christian Marquardt  Research Scientist
    Met Office   FitzRoy Road   Exeter   EX1 3PB   United Kingdom
    Tel: +44 (0)1392 88 4820   Fax: +44 (0)1392 885681
    E-mail: christian.marquardt AT metoffice.com   http://www.metoffice.com
    

    _______________________________________________ ncl-talk mailing list ncl-talk AT ucar.edu http://mailman.ucar.edu/mailman/listinfo/ncl-talk



    This archive was generated by hypermail 2b29 : Mon Feb 23 2004 - 08:34:13 MST