.TH argparse 3erl "stdlib 5.2.2" "Maxim Fedorov" "Erlang Module Definition" .SH NAME argparse \- Command line arguments parser. .SH DESCRIPTION .LP This module implements command line parser\&. Parser operates with \fIcommands\fR\& and \fIarguments\fR\& represented as a tree\&. Commands are branches, and arguments are leaves of the tree\&. Parser always starts with the root command, named after \fIprogname\fR\& (the name of the program which started Erlang)\&. .LP A \fIcommand specification\fR\& may contain handler definition for each command, and a number argument specifications\&. When parser is successful, \fIargparse\fR\& calls the matching handler, passing arguments extracted from the command line\&. Arguments can be positional (occupying specific position in the command line), and optional, residing anywhere but prefixed with a specified character\&. .LP \fIargparse\fR\& automatically generates help and usage messages\&. It will also issue errors when users give the program invalid arguments\&. .SH "QUICK START" .LP \fIargparse\fR\& is designed to work with \fIescript\fR\&\&. The example below is a fully functioning Erlang program accepting two command line arguments and printing their product\&. .LP .nf #!/usr/bin/env escript main(Args) -> argparse:run(Args, cli(), #{progname => mul}). cli() -> #{ arguments => [ #{name => left, type => integer}, #{name => right, type => integer} ], handler => fun (#{left := Left, right := Right}) -> io:format("~b~n", [Left * Right]) end }. .fi .LP Running this script with no arguments results in an error, accompanied by the usage information\&. .LP The \fIcli\fR\& function defines a single command with embedded handler accepting a map\&. Keys of the map are argument names as defined by the \fIargument\fR\& field of the command, \fIleft\fR\& and \fIright\fR\& in the example\&. Values are taken from the command line, and converted into integers, as requested by the type specification\&. Both arguments in the example above are required (and therefore defined as positional)\&. .SH "COMMAND HIERARCHY" .LP A command may contain nested commands, forming a hierarchy\&. Arguments defined at the upper level command are automatically added to all nested commands\&. Nested commands example (assuming \fIprogname\fR\& is \fInested\fR\&): .LP .nf cli() -> #{ %% top level argument applicable to all commands arguments => [#{name => top}], commands => #{ "first" => #{ %% argument applicable to "first" command and %% all commands nested into "first" arguments => [#{name => mid}], commands => #{ "second" => #{ %% argument only applicable for "second" command arguments => [#{name => bottom}], handler => fun (A) -> io:format("~p~n", [A]) end } } } } }. .fi .LP In the example above, a 3-level hierarchy is defined\&. First is the script itself (\fInested\fR\&), accepting the only argument \fItop\fR\&\&. Since it has no associated handler, run/3 will not accept user input omitting nested command selection\&. For this example, user has to supply 5 arguments in the command line, two being command names, and another 3 - required positional arguments: .LP .nf ./nested.erl one first second two three #{top => "one",mid => "two",bottom => "three"} .fi .LP Commands have preference over positional argument values\&. In the example above, commands and positional arguments are interleaving, and \fIargparse\fR\& matches command name first\&. .SH "ARGUMENTS" .LP \fIargparse\fR\& supports positional and optional arguments\&. Optional arguments, or options for short, must be prefixed with a special character (\fI-\fR\& is the default on all operating systems)\&. Both options and positional arguments have 1 or more associated values\&. See \fIargument specification\fR\& to find more details about supported combinations\&. .LP In the user input, short options may be concatenated with their values\&. Long options support values separated by \fI=\fR\&\&. Consider this definition: .LP .nf cli() -> #{ arguments => [ #{name => long, long => "-long"}, #{name => short, short => $s} ], handler => fun (Args) -> io:format("~p~n", [Args]) end }. .fi .LP Running \fI\&./args --long=VALUE\fR\& prints \fI#{long => "VALUE"}\fR\&, running \fI\&./args -sVALUE\fR\& prints \fI#{short => "VALUE"}\fR\& .LP \fIargparse\fR\& supports boolean flags concatenation: it is possible to shorten \fI-r -f -v\fR\& to \fI-rfv\fR\&\&. .LP Shortened option names are not supported: it is not possible to use \fI--my-argum\fR\& instead of \fI--my-argument-name\fR\& even when such option can be unambiguously found\&. .SH DATA TYPES .nf \fBarg_type()\fR\& = .br boolean | float | .br {float, Choice :: [float()]} | .br {float, [{min, float()} | {max, float()}]} | .br integer | .br {integer, Choices :: [integer()]} | .br {integer, [{min, integer()} | {max, integer()}]} | .br string | .br {string, Choices :: [string()]} | .br {string, Re :: string()} | .br {string, Re :: string(), ReOptions :: [term()]} | .br binary | .br {binary, Choices :: [binary()]} | .br {binary, Re :: binary()} | .br {binary, Re :: binary(), ReOptions :: [term()]} | .br atom | .br {atom, Choices :: [atom()]} | .br {atom, unsafe} | .br {custom, fun((string()) -> term())} .br .fi .RS .LP Defines type conversion applied to the string retrieved from the user input\&. If the conversion is successful, resulting value is validated using optional \fIChoices\fR\&, or minimums and maximums (for integer and floating point values only)\&. Strings and binary values may be validated using regular expressions\&. It\&'s possible to define custom type conversion function, accepting a string and returning Erlang term\&. If this function raises error with \fIbadarg\fR\& reason, argument is treated as invalid\&. .RE .nf \fBargument_help()\fR\& = .br {unicode:chardata(), .br [unicode:chardata() | type | default] | .br fun(() -> unicode:chardata())} .br .fi .RS .LP User-defined help template to print in the command usage\&. First element of a tuple must be a string\&. It is printed as a part of the usage header\&. Second element of the tuple can be either a list containing strings, \fItype\fR\& and \fIdefault\fR\& atoms, or a user-defined function that must return a string\&. A plain string should be wrapped as a list such as \fI["string is nested"]\fR\&\&. .RE .nf \fBargument_name()\fR\& = atom() | string() | binary() .br .fi .RS .LP Argument name is used to populate argument map\&. .RE .nf \fBargument()\fR\& = .br #{name := argument_name(), .br short => char(), .br long => string(), .br required => boolean(), .br default => term(), .br type => arg_type(), .br action => .br store | .br {store, term()} | .br append | .br {append, term()} | .br count | extend, .br nargs => .br integer() >= 1 | .br maybe | .br {maybe, term()} | .br list | nonempty_list | all, .br help => hidden | unicode:chardata() | argument_help()} .br .fi .RS .LP Argument specification\&. Defines a single named argument that is returned in the \fIargument map\fR\&\&. The only required field is \fIname\fR\&, all other fields have defaults\&. .LP If either of the \fIshort\fR\& or \fIlong\fR\& fields is specified, the argument is treated as optional\&. Optional arguments do not have specific order and may appear anywhere in the command line\&. Positional arguments are ordered the same way as they appear in the arguments list of the command specification\&. .LP By default, all positional arguments must be present in the command line\&. The parser will return an error otherwise\&. Options, however, may be omitted, in which case resulting argument map will either contain the default value, or not have the key at all\&. .RS 2 .TP 2 .B \fIname\fR\&: Sets the argument name in the parsed argument map\&. If \fIhelp\fR\& is not defined, name is also used to generate the default usage message\&. .TP 2 .B \fIshort\fR\&: Defines a short (single character) form of an optional argument\&. .LP .nf %% Define a command accepting argument named myarg, with short form $a: 1> Cmd = #{arguments => [#{name => myarg, short => $a}]}. %% Parse command line "-a str": 2> {ok, ArgMap, _, _} = argparse:parse(["-a", "str"], Cmd), ArgMap. #{myarg => "str"} %% Option value can be concatenated with the switch: "-astr" 3> {ok, ArgMap, _, _} = argparse:parse(["-astr"], Cmd), ArgMap. #{myarg => "str"} .fi .RS 2 .LP By default all options expect a single value following the option switch\&. The only exception is an option of a boolean type\&. .RE .TP 2 .B \fIlong\fR\&: Defines a long form of an optional argument\&. .LP .nf 1> Cmd = #{arguments => [#{name => myarg, long => "name"}]}. %% Parse command line "-name Erlang": 2> {ok, ArgMap, _, _} = argparse:parse(["-name", "Erlang"], Cmd), ArgMap. #{myarg => "Erlang"} %% Or use "=" to separate the switch and the value: 3> {ok, ArgMap, _, _} = argparse:parse(["-name=Erlang"], Cmd), ArgMap. #{myarg => "Erlang"} .fi .RS 2 .LP If neither \fIshort\fR\& not \fIlong\fR\& is defined, the argument is treated as positional\&. .RE .TP 2 .B \fIrequired\fR\&: Forces the parser to expect the argument to be present in the command line\&. By default, all positional argument are required, and all options are not\&. .TP 2 .B \fIdefault\fR\&: Specifies the default value to put in the parsed argument map if the value is not supplied in the command line\&. .LP .nf 1> argparse:parse([], #{arguments => [#{name => myarg, short => $m}]}). {ok,#{}, ... 2> argparse:parse([], #{arguments => [#{name => myarg, short => $m, default => "def"}]}). {ok,#{myarg => "def"}, ... .fi .TP 2 .B \fItype\fR\&: Defines type conversion and validation routine\&. The default is \fIstring\fR\&, assuming no conversion\&. .TP 2 .B \fInargs\fR\&: Defines the number of following arguments to consume from the command line\&. By default, the parser consumes the next argument and converts it into an Erlang term according to the specified type\&. .RS 2 .TP 2 .B \fIpos_integer()\fR\&: Consume exactly this number of positional arguments, fail if there is not enough\&. Value in the argument map contains a list of exactly this length\&. Example, defining a positional argument expecting 3 integer values: .LP .nf 1> Cmd = #{arguments => [#{name => ints, type => integer, nargs => 3}]}, argparse:parse(["1", "2", "3"], Cmd). {ok, #{ints => [1, 2, 3]}, ... .fi .RS 2 .LP Another example defining an option accepted as \fI-env\fR\& and expecting two string arguments: .RE .LP .nf 1> Cmd = #{arguments => [#{name => env, long => "env", nargs => 2}]}, argparse:parse(["-env", "key", "value"], Cmd). {ok, #{env => ["key", "value"]}, ... .fi .TP 2 .B \fIlist\fR\&: Consume all following arguments until hitting the next option (starting with an option prefix)\&. May result in an empty list added to the arguments map\&. .LP .nf 1> Cmd = #{arguments => [ #{name => nodes, long => "nodes", nargs => list}, #{name => verbose, short => $v, type => boolean} ]}, argparse:parse(["-nodes", "one", "two", "-v"], Cmd). {ok, #{nodes => ["one", "two"], verbose => true}, ... .fi .TP 2 .B \fInonempty_list\fR\&: Same as \fIlist\fR\&, but expects at least one argument\&. Returns an error if the following command line argument is an option switch (starting with the prefix)\&. .TP 2 .B \fI\&'maybe\&'\fR\&: Consumes the next argument from the command line, if it does not start with an option prefix\&. Otherwise, adds a default value to the arguments map\&. .LP .nf 1> Cmd = #{arguments => [ #{name => level, short => $l, nargs => 'maybe', default => "error"}, #{name => verbose, short => $v, type => boolean} ]}, argparse:parse(["-l", "info", "-v"], Cmd). {ok,#{level => "info",verbose => true}, ... %% When "info" is omitted, argument maps receives the default "error" 2> argparse:parse(["-l", "-v"], Cmd). {ok,#{level => "error",verbose => true}, ... .fi .TP 2 .B \fI{\&'maybe\&', term()}\fR\&: Consumes the next argument from the command line, if it does not start with an option prefix\&. Otherwise, adds a specified Erlang term to the arguments map\&. .TP 2 .B \fIall\fR\&: Fold all remaining command line arguments into a list, ignoring any option prefixes or switches\&. Useful for proxying arguments into another command line utility\&. .LP .nf 1> Cmd = #{arguments => [ #{name => verbose, short => $v, type => boolean}, #{name => raw, long => "-", nargs => all} ]}, argparse:parse(["-v", "--", "-kernel", "arg", "opt"], Cmd). {ok,#{raw => ["-kernel","arg","opt"],verbose => true}, ... .fi .RE .TP 2 .B \fIaction\fR\&: Defines an action to take when the argument is found in the command line\&. The default action is \fIstore\fR\&\&. .RS 2 .TP 2 .B \fIstore\fR\&: Store the value in the arguments map\&. Overwrites the value previously written\&. .LP .nf 1> Cmd = #{arguments => [#{name => str, short => $s}]}, argparse:parse(["-s", "one", "-s", "two"], Cmd). {ok, #{str => "two"}, ... .fi .TP 2 .B \fI{store, term()}\fR\&: Stores the specified term instead of reading the value from the command line\&. .LP .nf 1> Cmd = #{arguments => [#{name => str, short => $s, action => {store, "two"}}]}, argparse:parse(["-s"], Cmd). {ok, #{str => "two"}, ... .fi .TP 2 .B \fIappend\fR\&: Appends the repeating occurrences of the argument instead of overwriting\&. .LP .nf 1> Cmd = #{arguments => [#{name => node, short => $n, action => append}]}, argparse:parse(["-n", "one", "-n", "two", "-n", "three"], Cmd). {ok, #{node => ["one", "two", "three"]}, ... %% Always produces a list - even if there is one occurrence 2> argparse:parse(["-n", "one"], Cmd). {ok, #{node => ["one"]}, ... .fi .TP 2 .B \fI{append, term()}\fR\&: Same as \fIappend\fR\&, but instead of consuming the argument from the command line, appends a provided \fIterm()\fR\&\&. .TP 2 .B \fIcount\fR\&: Puts a counter as a value in the arguments map\&. Useful for implementing verbosity option: .LP .nf 1> Cmd = #{arguments => [#{name => verbose, short => $v, action => count}]}, argparse:parse(["-v"], Cmd). {ok, #{verbose => 1}, ... 2> argparse:parse(["-vvvv"], Cmd). {ok, #{verbose => 4}, ... .fi .TP 2 .B \fIextend\fR\&: Works as \fIappend\fR\&, but flattens the resulting list\&. Valid only for \fInargs\fR\& set to \fIlist\fR\&, \fInonempty_list\fR\&, \fIall\fR\& or \fIpos_integer()\fR\&\&. .LP .nf 1> Cmd = #{arguments => [#{name => duet, short => $d, nargs => 2, action => extend}]}, argparse:parse(["-d", "a", "b", "-d", "c", "d"], Cmd). {ok, #{duet => ["a", "b", "c", "d"]}, ... %% 'append' would result in {ok, #{duet => [["a", "b"],["c", "d"]]}, .fi .RE .TP 2 .B \fIhelp\fR\&: Specifies help/usage text for the argument\&. \fIargparse\fR\& provides automatic generation based on the argument name, type and default value, but for better usability it is recommended to have a proper description\&. Setting this field to \fIhidden\fR\& suppresses usage output for this argument\&. .RE .RE .nf \fBarg_map()\fR\& = #{argument_name() => term()} .br .fi .RS .LP Arguments map is the map of argument names to the values extracted from the command line\&. It is passed to the matching command handler\&. If an argument is omitted, but has the default value is specified, it is added to the map\&. When no default value specified, and argument is not present in the command line, corresponding key is not present in the resulting map\&. .RE .nf \fBhandler()\fR\& = .br optional | .br fun((arg_map()) -> term()) | .br {module(), Fn :: atom()} | .br {fun(() -> term()), term()} | .br {module(), atom(), term()} .br .fi .RS .LP Command handler specification\&. Called by \fIrun/3\fR\& upon successful parser return\&. .RS 2 .TP 2 .B \fIfun((arg_map()) -> term())\fR\&: Function accepting \fIargument map\fR\&\&. See the basic example in the Quick Start section\&. .TP 2 .B \fI{Module :: module(), Function :: atom()}\fR\&: Function named \fIFunction\fR\&, exported from \fIModule\fR\&, accepting \fIargument map\fR\&\&. .TP 2 .B \fI{fun(() -> term()), Default :: term()}\fR\&: Function accepting as many arguments as there are in the \fIarguments\fR\& list for this command\&. Arguments missing from the parsed map are replaced with the \fIDefault\fR\&\&. Convenient way to expose existing functions\&. .LP .nf 1> Cmd = #{arguments => [ #{name => x, type => float}, #{name => y, type => float, short => $p}], handler => {fun math:pow/2, 1}}, argparse:run(["2", "-p", "3"], Cmd, #{}). 8.0 %% default term 1 is passed to math:pow/2 2> argparse:run(["2"], Cmd, #{}). 2.0 .fi .TP 2 .B \fI{Module :: module(), Function :: atom(), Default :: term()}\fR\&: Function named \fIFunction\fR\&, exported from \fIModule\fR\&, accepting as many arguments as defined for this command\&. Arguments missing from the parsed map are replaced with the \fIDefault\fR\&\&. Effectively, just a different syntax to the same functionality as demonstrated in the code above\&. .RE .RE .nf \fBcommand_help()\fR\& = .br [unicode:chardata() | usage | commands | arguments | options] .br .fi .RS .LP User-defined help template\&. Use this option to mix custom and predefined usage text\&. Help template may contain unicode strings, and following atoms: .RS 2 .TP 2 .B usage: Formatted command line usage text, e\&.g\&. \fIrm [-rf] \fR\&\&. .TP 2 .B commands: Expanded list of sub-commands\&. .TP 2 .B arguments: Detailed description of positional arguments\&. .TP 2 .B options: Detailed description of optional arguments\&. .RE .RE .nf \fBcommand()\fR\& = .br #{commands => #{string() => command()}, .br arguments => [argument()], .br help => hidden | unicode:chardata() | command_help(), .br handler => handler()} .br .fi .RS .LP Command specification\&. May contain nested commands, forming a hierarchy\&. .RS 2 .TP 2 .B \fIcommands\fR\&: Maps of nested commands\&. Keys must be strings, matching command line input\&. Basic utilities do not need to specify any nested commands\&. .TP 2 .B \fIarguments\fR\&: List of arguments accepted by this command, and all nested commands in the hierarchy\&. .TP 2 .B \fIhelp\fR\&: Specifies help/usage text for this command\&. Pass \fIhidden\fR\& to remove this command from the usage output\&. .TP 2 .B \fIhandler\fR\&: Specifies a callback function to call by run/3 when the parser is successful\&. .RE .RE .nf \fBcmd_path()\fR\& = [string()] .br .fi .RS .LP Path to the nested command\&. First element is always the \fIprogname\fR\&, subsequent elements are nested command names\&. .RE .nf \fBparser_error()\fR\& = .br {Path :: cmd_path(), .br Expected :: argument() | undefined, .br Actual :: string() | undefined, .br Details :: unicode:chardata()} .br .fi .RS .LP Returned from \fIparse/2,3\fR\& when the user input cannot be parsed according to the command specification\&. .LP First element is the path to the command that was considered when the parser detected an error\&. Second element, \fIExpected\fR\&, is the argument specification that caused an error\&. It could be \fIundefined\fR\&, meaning that \fIActual\fR\& argument had no corresponding specification in the arguments list for the current command\&. .LP When \fIActual\fR\& is set to \fIundefined\fR\&, it means that a required argument is missing from the command line\&. If both \fIExpected\fR\& and \fIActual\fR\& have values, it means validation error\&. .LP Use \fIformat_error/1\fR\& to generate a human-readable error description, unless there is a need to provide localised error messages\&. .RE .nf \fBparser_options()\fR\& = .br #{prefixes => [char()], .br default => term(), .br progname => string() | atom(), .br command => cmd_path(), .br columns => integer() >= 1} .br .fi .RS .LP Options changing parser behaviour\&. .RS 2 .TP 2 .B \fIprefixes\fR\&: Changes the option prefix (the default is \fI-\fR\&)\&. .TP 2 .B \fIdefault\fR\&: Specifies the default value for all optional arguments\&. When this field is set, resulting argument map will contain all argument names\&. Useful for easy pattern matching on the argument map in the handler function\&. .TP 2 .B \fIprogname\fR\&: Specifies the program (root command) name\&. Returned as the first element of the command path, and printed in help/usage text\&. It is recommended to have this value set, otherwise the default one is determined with \fIinit:get_argument(progname)\fR\& and is often set to \fIerl\fR\& instead of the actual script name\&. .TP 2 .B \fIcommand\fR\&: Specifies the path to the nested command for \fIhelp/2\fR\&\&. Useful to limit output for complex utilities with multiple commands, and used by the default error handling logic\&. .TP 2 .B \fIcolumns\fR\&: Specifies the help/usage text width (characters) for \fIhelp/2\fR\&\&. Default value is 80\&. .RE .RE .nf \fBparse_result()\fR\& = .br {ok, arg_map(), Path :: cmd_path(), command()} | .br {error, parser_error()} .br .fi .RS .LP Returned from \fIparse/2,3\fR\&\&. Contains arguments extracted from the command line, path to the nested command (if any), and a (potentially nested) command specification that was considered when the parser finished successfully\&. It is expected that the command contains a handler definition, that will be called passing the argument map\&. .RE .SH EXPORTS .LP .nf .B format_error(Reason :: parser_error()) -> unicode:chardata() .br .fi .br .RS .LP Generates human-readable text for \fIparser error\fR\&\&. Does not include help/usage information, and does not provide localisation\&. .RE .LP .nf .B help(Command :: command()) -> string() .br .fi .br .nf .B help(Command :: command(), Options :: parser_options()) -> .B unicode:chardata() .br .fi .br .RS .LP Generates help/usage information text for the command supplied, or any nested command when \fIcommand\fR\& option is specified\&. Arguments are displayed in the same order as specified in \fICommand\fR\&\&. Does not provide localisation\&. Expects \fIprogname\fR\& to be set, otherwise defaults to return value of \fIinit:get_argument(progname)\fR\&\&. .RE .LP .nf .B parse(Args :: [string()], Command :: command()) -> parse_result() .br .fi .br .nf .B parse(Args :: [string()], .B Command :: command(), .B Options :: parser_options()) -> .B parse_result() .br .fi .br .RS .LP Parses command line arguments according to the command specification\&. Raises an exception if the command specification is not valid\&. Use \fIerl_error:format_exception/3,4\fR\& to see a friendlier message\&. Invalid command line input does not raise an exception, but makes \fIparse/2,3\fR\& to return a tuple \fI{error, parser_error()}\fR\&\&. .LP This function does not call command handler\&. .RE .LP .nf .B run(Args :: [string()], .B Command :: command(), .B Options :: parser_options()) -> .B term() .br .fi .br .RS .LP Parses command line arguments and calls the matching command handler\&. Prints human-readable error, help/usage information for the discovered command, and halts the emulator with code 1 if there is any error in the command specification or user-provided command line input\&. .LP .RS -4 .B Warning: .RE This function is designed to work as an entry point to a standalone \fIescript\fR\&\&. Therefore, it halts the emulator for any error detected\&. Do not use this function through remote procedure call, or it may result in an unexpected shutdown of a remote node\&. .RE