The ability to accept and handle command line arguments is very important when writing Guile scripts to solve particular problems, such as extracting information from text files or interfacing with existing command line applications. This chapter describes how Guile makes command line arguments available to a Guile script, and the utilities that Guile provides to help with the processing of command line arguments.
When a Guile script is invoked, Guile makes the command line arguments
accessible via the procedure command-line, which returns the
arguments as a list of strings.
For example, if the script
#! /usr/local/bin/guile -s !# (write (command-line)) (newline)
is saved in a file `cmdline-test.scm' and invoked using the command
line ./cmdline-test.scm bar.txt -o foo -frumple grob, the output
is
("./cmdline-test.scm" "bar.txt" "-o" "foo" "-frumple" "grob")
If the script invocation includes a -e option, specifying a
procedure to call after loading the script, Guile will call that
procedure with (command-line) as its argument. So a script that
uses -e doesn't need to refer explicitly to command-line
in its code. For example, the script above would have identical
behaviour if it was written instead like this:
#! /usr/local/bin/guile \ -e main -s !# (define (main args) (write args) (newline))
(Note the use of the meta switch \ so that the script invocation
can include more than one Guile option: See section The Meta Switch.)
These scripts use the #! POSIX convention so that they can be
executed using their own file names directly, as in the example command
line ./cmdline-test.scm bar.txt -o foo -frumple grob. But they
can also be executed by typing out the implied Guile command line in
full, as in:
$ guile -s ./cmdline-test.scm bar.txt -o foo -frumple grob
or
$ guile -e main -s ./cmdline-test2.scm bar.txt -o foo -frumple grob
Even when a script is invoked using this longer form, the arguments that
the script receives are the same as if it had been invoked using the
short form. Guile ensures that the (command-line) or -e
arguments are independent of how the script is invoked, by stripping off
the arguments that Guile itself processes.
A script is free to parse and handle its command line arguments in any
way that it chooses. Where the set of possible options and arguments is
complex, however, it can get tricky to extract all the options, check
the validity of given arguments, and so on. This task can be greatly
simplified by taking advantage of the module (ice-9 getopt-long),
which is distributed with Guile.
The (ice-9 getopt-long) module exports two procedures:
getopt-long and option-ref.
getopt-long takes a list of strings -- the command line
arguments -- and an option specification. It parses the command
line arguments according to the option specification and returns a data
structure that encapsulates the results of the parsing.
option-ref then takes the parsed data structure and a specific
option's name, and returns information about that option in particular.
To make these procedures available to your Guile script, include the
expression (use-modules (ice-9 getopt-long)) somewhere near the
top, before the first usage of getopt-long or option-ref.
This subsection illustrates how getopt-long is used by presenting
and dissecting a simple example. The first thing that we need is an
option specification that tells getopt-long how to parse
the command line. This specification is an association list with the
long option name as the key. Here is how such a specification might
look:
(define option-spec
'((version (single-char #\v) (value #f))
(help (single-char #\h) (value #f))))
This alist tells getopt-long that it should accept two long
options, called version and help, and that these options
can also be selected by the single-letter abbreviations v and
h, respectively. The (value #f) clauses indicate that
neither of the options accepts a value.
With this specification we can use getopt-long to parse a given
command line:
(define options (getopt-long (command-line) option-spec))
After this call, options contains the parsed command line and is
ready to be examined by option-ref. option-ref is called
like this:
(option-ref options 'help #f)
It expects the parsed command line, a symbol indicating the option to
examine, and a default value. The default value is returned if the
option was not present in the command line, or if the option was present
but without a value; otherwise the value from the command line is
returned. Usually option-ref is called once for each possible
option that a script supports.
The following example shows a main program which puts all this together to parse its command line and figure out what the user wanted.
(define (main args)
(let* ((option-spec '((version (single-char #\v) (value #f))
(help (single-char #\h) (value #f))))
(options (getopt-long args option-spec))
(help-wanted (option-ref options 'help #f))
(version-wanted (option-ref options 'version #f)))
(if (or version-wanted help-wanted)
(begin
(if version-wanted
(display "getopt-long-example version 0.3\n"))
(if help-wanted
(display "\
getopt-long-example [options]
-v, --version Display version
-h, --help Display this help
")))
(begin
(display "Hello, World!") (newline)))))
An option specification is an association list (see section Association Lists) with one list element for each supported option. The key of each list element is a symbol that names the option, while the value is a list of option properties:
OPTION-SPEC ::= '( (OPT-NAME1 (PROP-NAME PROP-VALUE) ...)
(OPT-NAME2 (PROP-NAME PROP-VALUE) ...)
(OPT-NAME3 (PROP-NAME PROP-VALUE) ...)
...
)
Each opt-name specifies the long option name for that option. For
example, a list element with opt-name background specifies
an option that can be specified on the command line using the long
option --background. Further information about the option ---
whether it takes a value, whether it is required to be present in the
command line, and so on -- is specified by the option properties.
In the example of the preceding subsection, we already saw that a long
option name can have a equivalent short option character. The
equivalent short option character can be set for an option by specifying
a single-char property in that option's property list. For
example, a list element like '(output (single-char #\o) ...)
specifies an option with long name --output that can also be
specified by the equivalent short name -o.
The value property specifies whether an option requires or
accepts a value. If the value property is set to #t, the
option requires a value: getopt-long will signal an error if the
option name is present without a corresponding value. If set to
#f, the option does not take a value; in this case, a non-option
word that follows the option name in the command line will be treated as
a non-option argument. If set to the symbol optional, the option
accepts a value but does not require one: a non-option word that follows
the option name in the command line will be interpreted as that option's
value. If the option name for an option with '(value optional)
is immediately followed in the command line by another option
name, the value for the first option is implicitly #t.
The required? property indicates whether an option is required to
be present in the command line. If the required? property is
set to #t, getopt-long will signal an error if the option
is not specified.
Finally, the predicate property can be used to constrain the
possible values of an option. If used, the predicate property
should be set to a procedure that takes one argument -- the proposed
option value as a string -- and returns either #t or #f
according as the proposed value is or is not acceptable. If the
predicate procedure returns #f, getopt-long will signal an
error.
By default, options do not have single-character equivalents, are not
required, and do not take values. Where the list element for an option
includes a value property but no predicate property, the
option values are unconstrained.
In order for getopt-long to correctly parse a command line, that
command line must conform to a standard set of rules for how command
line options are specified. This subsection explains what those rules
are.
getopt-long splits a given command line into several pieces. All
elements of the argument list are classified to be either options or
normal arguments. Options consist of two dashes and an option name
(so-called long options), or of one dash followed by a single
letter (short options).
Options can behave as switches, when they are given without a value, or they can be used to pass a value to the program. The value for an option may be specified using an equals sign, or else is simply the next word in the command line, so the following two invocations are equivalent:
$ ./foo.scm --output=bar.txt $ ./foo.scm --output bar.txt
Short options can be used instead of their long equivalents and can be grouped together after a single dash. For example, the following commands are equivalent.
$ ./foo.scm --version --help $ ./foo.scm -v --help $ ./foo.scm -vh
If an option requires a value, it can only be grouped together with other short options if it is the last option in the group; the value is the next argument. So, for example, with the following option specification ---
((apples (single-char #\a)) (blimps (single-char #\b) (value #t)) (catalexis (single-char #\c) (value #t)))
--- the following command lines would all be acceptable:
$ ./foo.scm -a -b bang -c couth $ ./foo.scm -ab bang -c couth $ ./foo.scm -ac couth -b bang
But the next command line is an error, because -b is not the last
option in its combination, and because a group of short options cannot
include two options that both require values:
$ ./foo.scm -abc couth bang
If an option's value is optional, getopt-long decides whether the
option has a value by looking at what follows it in the argument list.
If the next element is a string, and it does not appear to be an option
itself, then that string is the option's value.
If the option -- appears in the argument list, argument parsing
stops there and subsequent arguments are returned as ordinary arguments,
even if they resemble options. So, with the command line
$ ./foo.scm --apples "Granny Smith" -- --blimp Goodyear
getopt-long will recognize the --apples option as having
the value "Granny Smith", but will not treat --blimp as an
option. The strings --blimp and Goodyear will be returned
as ordinary argument strings.
getopt-long
The grammar argument is expected to be a list of this form:
((option (property value) ...) ...)
where each option is a symbol denoting the long option, but
without the two leading dashes (e.g. version if the option is
called --version).
For each option, there may be list of arbitrarily many property/value pairs. The order of the pairs is not important, but every property may only appear once in the property list. The following table lists the possible properties:
(single-char char)
-char as a single-character equivalent to
--option. This is how to specify traditional Unix-style
flags.
(required? bool)
getopt-long will
raise an error if it is not found in args.
(value bool)
#t, the option accepts a value; if it is
#f, it does not; and if it is the symbol optional, the
option may appear in args with or without a value.
(predicate func)
(value #t) for
this option), then getopt-long will apply func to the
value, and throw an exception if it returns #f. func
should be a procedure which accepts a string and returns a boolean
value; you may need to use quasiquotes to get it into grammar.
getopt-long's args parameter is expected to be a list of
strings like the one returned by command-line, with the first
element being the name of the command. Therefore getopt-long
ignores the first element in args and starts argument
interpretation with the second element.
getopt-long signals an error if any of the following conditions
hold.
--opt=value syntax).
option-ref
#t. If the option was not given, return default.
options must be the result of a call to getopt-long.
option-ref always succeeds, either by returning the requested
option value from the command line, or the default value.
The special key '() can be used to get a list of all
non-option arguments.
Go to the first, previous, next, last section, table of contents.