User Tools

Site Tools


usages:argp.sh
Usage: argp [OPTION...] [--] [args ...]

A wrapper for getopt(1) which simulates argp(3) for bash. Normally
other scripts pipe their option descriptions in here for automatic
help and man-page production and for generating the code for
getopt(1). Requires bash-3+. See also argp(1) which is a binary (and
much faster) version of this.

See http://sourceforge.net/projects/argpsh
See http://bhepple.freeshell.org/oddmuse/wiki.cgi/argp.sh

It buys you:

o all the goodness of getopt
o define options in one central place together with descriptions using a
  simple flat file format or XML.
o fewer 'magic' and duplicated values in your code
o automatic consistency between the getopt calling parameters, the case
  statement processing the user's options and the help/man pages
o less spaghetti in your own code
o easier to maintain
o help-page and man-page printing - all from the same data sources
o checking of option consistency at runtime
o range checking of option values at runtime
o pretty easy to use
o portable to OS's without long option support - the help page
  adapts too

###############################################################################

Usage: argp.sh / argp reads its configuration from stdin (fd0) (see
below for details) and outputs the following:

* --help output on stdout fd1
* errors on stderr fd2
* a list of commands on fd3

The calling program can then 'eval' that list of commands in order to
set environment variables as set by the user in command line options.
Also, any remaining arguments after the options are removed are set to
$1 $2 ...

eg. if the user typed 'myprog --foobar --barfoo=three a b c' then after
'eval'ing the fd3 output of argp.sh / argp you would have
FOOBAR="set"
BARFOO="three"
$1 $2 ... = a b c

Usually, the calling program would invoke argp.sh / argp like this:

    exec 4>&1
    eval "$(echo "$ARGS" | argp.sh "$@" 3>&1 1>&4 || echo exit $? )"
    exec 4>&-

Here's a bit of an explanation in case you're interested:
    exec 4>&1  # make fd4 a copy of fd1 stdout eg /dev/pts/0, the terminal
    eval $(
        # inside this sub-shell fd1 is now a pipe
        echo "$ARGS" |

        # 3>&1: connect fd3 to fd1 (the pipe) so that anything printed
        # on fd3 is fed to the pipe (and eventually eval'd).
        #
        # 1>&4: fd1 is connected to fd4 ie /dev/pts/0 so that anything
        # that argp.sh / argp prints on stdout (eg the --help output) ends up
        # on the terminal:

        argp.sh "$@" 3>&1 1>&4 || echo exit $?
    )
    exec 4>&- # close fd4

###############################################################################

It's easier to look at a running script but here's the manual:

###############################################################################

this is a comment.

# The following line defines our program name. We might also write
# this as ARGP_PROG=$(basename $0):
ARGP_PROG=my-script

# '--quiet' is a built-in option, but we normally delete it if 'verbose' is
# supported.
ARGP_DELETE=quiet

# this defines the program's version string to be displayed by the -V option:
ARGP_VERSION=1.6

# this string is added as a prefix to all option names on output, eg
if you need to use an option that clashes with a system environment
parameter eg --home:
ARGP_PREFIX=FOO_

# if this is set then multiple invocations of a string or array option will
# be concatenated using this separator eg '-s s -s b' will give 'a:b'
ARGP_OPTION_SEP=:

# Here are the options that this program will accept:
########       ##### ###     #### #####   ###########
# name         sname arg     type range   description
########       ##### ###     #### #####   ###########

name=default : 'name' must be present and unique. 'default' must be given but
               may be ''

sname        : the single-letter short name of the option (use '' if a short
               name is not needed)

arg          : the name of the argument to be used in --help (not for
               booleans)

type         : b (boolean), i (integer), d (double), s[:] (string),
               a[:] (array) or u (url). Default is boolean if arg is
               not given, otherwise string. If a boolean is
               initialised to '0', then it is incremented every time
               it is given. If a boolean is initialised to anything
               else then it flips between 'default' and 'range' every
               time it is given. If 's:' or 'a:' then ':' overrides
               ARGP_OPTION_SEP for this option. Any syntactically
               clean string can be used instead of ':' ie not ' or ".

range        : for numeric options: min:max eg 1.2:4.5 or min-max eg 1-3
               for string options: an extended regexp
               for array options: a space separated list of alternates
               in quotes "..." or '...'
               for boolean options: the value to assign the option when set

desc         : leave empty for hidden options. Long descriptions can
               span lines by putting '\' at the end of the line and by
               terminated the description with a '.' in the first
               column.

###############################################################################

xamples:

# This is the simplest possible option definition. It specifies a
# hidden option (--hidden) which does not appear in the help or man
# pages. It defaults to being a simple flag (boolean) with a default
# value of '' and 'set' if --hidden is on the command line.
HIDDEN=

# a boolean option with a short name and a numeric default which is
# incremented every time the --bool, -b option is given:
BOOL='0'       b     ''      b    ''      description of this option

# this is a (boolean) flag which gets set to the string 'foobar' when
# --flag, -f is on the command line otherwise it is set to 'barfoo':
FLAG='barfoo' f    ''      b    'foobar'  a flag

# here is an integer value option which must sit in a given range:
INT=1         i     units   i    '1:3'  an integer.

# here is an array value ie just a string which must take one of
# the values in the 'range':
ARRAY=a        a     widgets a    'a b'  an array

# this option is a simple string which will be checked against a regex(7):
STRING=''      s     string  s    '^foo.*bar$|^$'  a string.

# a double value which is checked against a range:
DOUBLE=1       d     miles   d    0.1:1.3 a double.

# this is a URL which will be checked against the URL regex and has a
# default value
URL='http://www.foobar.com'     u     url     u    ''      a url.

# delete this one as we want to use the 'q' option for something else:
ARGP_DELETE=quiet

# this uses the same short letter 'q' as the --quiet option which was
# deleted above
QUAINT=''      q     ''      s    ''      a quaint description

# here we define the non-option arguments that the command takes:
ARGP_ARGS= [--] [args]
ARGP_SHORT=This is a short description for the first line of the man page.
ARGP_USAGE=
This is a longer description.
Spring the flangen dump. Spring the flingen dump. Spring the flangen
dump. Spring the flingen dump.

###############################################################################

XML can also be instead of the above (provided xmlstarlet is available):

<?xml version="1.0" encoding="UTF-8"?>
<argp>
  <prog>fs</prog>
  <args>[--] [pattern]</args>
  <short>Search for filenames in sub-directories.</short>
  <delete>quiet</delete>
  <version>1.2</version>
  <prefix>FOO_</prefix>
  <usage>Presently this is just a shorthand for:

find . -follow \$EXCLUDE -type $TYPE -name '*pattern*' -print 2>/dev/null
|sort
  </usage>
  <option name="EXCLUDE" sname="x" type="s" arg="directory">exclude
directory</option>
  <option name="DIR"     sname="d" type="b" default="f" range="d">search for a
directory rather than a file</option>
  <option name="SECRET" type="b"/>
</argp>

Note that the attribute 'name' is required - the others are all
optional. Also the option value should be on a single line (the
program usage can be on multiple lines).

###############################################################################

Note that --verbose, --help, --quiet and --version options will be
added automatically. Also, a hidden option '--print-man-page' is
provided to print a skeleton man(1) page which can be used as the
starting point for a full man page. Another hidden option
'--print-xml' prints out the XML equivalent of the argp input.

If POSIXLY_CORRECT is set, then option parsing will end on the first
non-option argument (eg like ssh(1)).

###############################################################################

Here is a sample of the output when the command is called with --help:

Usage: my-script [OPTION...] [--] [args]
This is a longer description. Spring the flangen dump. Spring the
flingen dump. Spring the flangen dump. Spring the flingen dump."

Options:

  -a, --array=<widgets>      an array Must be of type 'a'. Must be in the
range
                             'a b'.
  -b, --bool                 description of this option
  -d, --double=<miles>       a double. Must be of type 'd'. Must be in the
                             range '0.1-1.3'.
  -f, --flag                 a flag
  -i, --int=<units>          an integer. Must be of type 'i'. Must be in the
                             range '1-3'.
  -q, --quaint               a quaint description Must fit the regex ''.
  -s, --string=<string>      a string. Must fit the regex '^foo.*bar$|^$'.
  -u, --url=<url>            a url. Must fit the regex
'^(nfs|http|https|ftp|file)://[[:alnum:]_.-]*[^[:space:]]*$'.
  -v, --verbose              be verbose
  -h, --help                 print this help message
  -V, --version              print version and exit

Options:

  -q, --quiet                be quiet
  -v, --verbose              be verbose
  -h, --help                 print this help message
  -V, --version              print version and exit
usages/argp.sh.txt · Last modified: 2019/07/09 09:57 (external edit)