查看源代码 OptionParser (Elixir v1.16.2)
用于解析命令行参数的函数。
在调用命令时,可以传递命令行选项来修改命令的行为。在本文档中,这些选项被称为“开关”,在其他情况下,它们可能被称为“标志”或简称“选项”。开关可以被赋予一个值,也称为“参数”。
此模块中的主要函数是 parse/2
,它将命令行选项和参数列表解析为关键字列表。
iex> OptionParser.parse(["--debug"], strict: [debug: :boolean])
{[debug: true], [], []}
OptionParser
提供了一些开箱即用的便利功能,例如别名和对否定开关的自动处理。
The parse_head/2
function is an alternative to parse/2
which stops parsing as soon as it finds a value that is not a switch nor a value for a previous switch.
此模块还提供低级函数,例如 next/2
,用于手动解析开关,以及 split/1
和 to_argv/1
用于从字符串解析开关并将其转换为字符串。
摘要
函数
解析单个选项的低级函数。
将 argv
解析为关键字列表。
与 parse/2
相同,但如果提供任何无效选项,则会引发 OptionParser.ParseError
异常。
与 parse/2
类似,但只解析 argv
的头部;一旦找到非开关,它就会停止解析。
与 parse_head/2
相同,但如果提供任何无效选项,则会引发 OptionParser.ParseError
异常。
将字符串拆分为 argv/0
块。
接收键值可枚举并将其转换为 argv/0
.
类型
函数
@spec next(argv(), options()) :: {:ok, key :: atom(), value :: term(), argv()} | {:invalid, String.t(), String.t() | nil, argv()} | {:undefined, String.t(), String.t() | nil, argv()} | {:error, argv()}
解析单个选项的低级函数。
它接受与 parse/2
和 parse_head/2
相同的选项,因为这两个函数都是基于此函数构建的。此函数可能会返回
{:ok, key, value, rest}
- 成功解析了带有value
的选项key
{:invalid, key, value, rest}
- 选项key
无效,带有value
(当值无法根据开关类型解析时返回){:undefined, key, value, rest}
- 选项key
未定义(在严格模式下返回,当开关未知或在不存在的原子上时返回){:error, rest}
- 给定argv
的头部没有开关
将 argv
解析为关键字列表。
它返回一个三元素元组,形式为 {parsed, args, invalid}
,其中
parsed
是一个关键字列表,包含解析的开关,其中包含{switch_name, value}
元组;switch_name
是表示开关名称的原子,而value
是根据opts
解析的该开关的值(有关更多信息,请参阅“示例”部分)args
是argv
中剩余参数的列表,作为字符串invalid
是一个无效选项的列表,作为{option_name, value}
,其中option_name
是原始选项,而value
是nil
(如果选项不受期望)或字符串值(如果值没有相应的选项的期望类型)
Elixir 将开关转换为带下划线的原子,因此 --source-path
变为 :source_path
。这样做是为了更好地适应 Elixir 的约定。但是,这意味着开关不能包含下划线,并且包含下划线的开关始终在无效开关列表中返回。
在解析时,通常列出开关及其预期的类型
iex> OptionParser.parse(["--debug"], strict: [debug: :boolean])
{[debug: true], [], []}
iex> OptionParser.parse(["--source", "lib"], strict: [source: :string])
{[source: "lib"], [], []}
iex> OptionParser.parse(
...> ["--source-path", "lib", "test/enum_test.exs", "--verbose"],
...> strict: [source_path: :string, verbose: :boolean]
...> )
{[source_path: "lib", verbose: true], ["test/enum_test.exs"], []}
我们将在下面探讨选项解析器的有效开关和操作模式。
选项
支持以下选项
:switches
或:strict
- 请参阅下面的“开关定义”部分:allow_nonexistent_atoms
- 请参阅下面的“解析未知开关”部分:aliases
- 请参阅下面的“别名”部分:return_separator
- 请参阅下面的“返回分隔符”部分
开关定义
可以通过以下两种选项之一指定开关
:strict
- 定义严格的开关及其类型。在argv
中,任何未在列表中指定的开关都会在无效选项列表中返回。这是解析选项的首选方法。:switches
- 定义开关及其类型。此函数仍然尝试解析不在此列表中的开关。
这两个选项都接受关键字列表,其中键是定义开关名称的原子,值是开关的 type
(有关更多信息,请参阅下面的“类型”部分)。
请注意,您应该只提供 :switches
或 :strict
选项。如果您同时提供两者,则会引发 ArgumentError
异常。
类型
由 OptionParser
解析的开关可以接受零个或一个参数。
以下开关类型不接受参数
:boolean
- 在给出时将值设置为true
(另请参阅下面的“否定开关”部分):count
- 统计开关被给出的次数
以下开关接受一个参数
:integer
- 将值解析为整数:float
- 将值解析为浮点数:string
- 将值解析为字符串
如果开关无法根据给定的类型解析,则它将在无效选项列表中返回。
修饰符
开关可以使用修饰符指定,这些修饰符会改变它们的行为。支持以下修饰符
:keep
- 保留重复元素,而不是覆盖它们;适用于除:count
之外的所有类型。指定switch_name: :keep
假设:switch_name
的类型将为:string
。
要将 :keep
与 :string
以外的类型一起使用,请使用列表作为开关的类型。例如:[foo: [:integer, :keep]]
。
否定开关
如果指定开关 SWITCH
的类型为 :boolean
,则也可以将其作为 --no-SWITCH
传递,这将使选项设置为 false
iex> OptionParser.parse(["--no-op", "path/to/file"], switches: [op: :boolean])
{[op: false], ["path/to/file"], []}
解析未知开关
当给出 :switches
选项时,OptionParser
将尝试解析未知开关
iex> OptionParser.parse(["--debug"], switches: [key: :string])
{[debug: true], [], []}
即使我们没有在开关列表中指定 --debug
,它也是返回选项的一部分。这也会有效
iex> OptionParser.parse(["--debug", "value"], switches: [key: :string])
{[debug: "value"], [], []}
带有值的开关将被赋予该值,作为字符串。没有参数的开关将自动设置为 true
。由于我们无法断言开关值的类型,因此最好使用 :strict
选项,该选项只接受已知开关并始终验证其类型。
如果您确实要解析未知开关,请记住 Elixir 会将开关转换为原子。由于原子不会被垃圾回收,OptionParser 只会解析转换为运行时使用的原子的开关,以避免泄漏原子。例如,下面的代码将丢弃 --option-parser-example
开关,因为 :option_parser_example
原子在任何地方都没有使用
OptionParser.parse(["--option-parser-example"], switches: [debug: :boolean])
# The :option_parser_example atom is not used anywhere below
但是,下面的代码将有效,只要 :option_parser_example
原子在稍后(或更早)在 **同一个模块** 中使用。例如
{opts, _, _} = OptionParser.parse(["--option-parser-example"], switches: [debug: :boolean])
# ... then somewhere in the same module you access it ...
opts[:option_parser_example]
换句话说,Elixir 仅解析运行时使用的选项,忽略所有其他选项。如果您想解析所有开关,无论它们是否存在,都可以通过传递 allow_nonexistent_atoms: true
作为选项来强制创建原子。谨慎使用此选项。它仅在您构建接收动态命名参数的命令行应用程序时有用,必须在长期运行的系统中避免。
别名
可以在 :aliases
选项中指定一组别名
iex> OptionParser.parse(["-d"], aliases: [d: :debug], strict: [debug: :boolean])
{[debug: true], [], []}
示例
以下是一些使用不同类型和修饰符的示例
iex> OptionParser.parse(["--unlock", "path/to/file"], strict: [unlock: :boolean])
{[unlock: true], ["path/to/file"], []}
iex> OptionParser.parse(
...> ["--unlock", "--limit", "0", "path/to/file"],
...> strict: [unlock: :boolean, limit: :integer]
...> )
{[unlock: true, limit: 0], ["path/to/file"], []}
iex> OptionParser.parse(["--limit", "3"], strict: [limit: :integer])
{[limit: 3], [], []}
iex> OptionParser.parse(["--limit", "xyz"], strict: [limit: :integer])
{[], [], [{"--limit", "xyz"}]}
iex> OptionParser.parse(["--verbose"], switches: [verbose: :count])
{[verbose: 1], [], []}
iex> OptionParser.parse(["-v", "-v"], aliases: [v: :verbose], strict: [verbose: :count])
{[verbose: 2], [], []}
iex> OptionParser.parse(["--unknown", "xyz"], strict: [])
{[], ["xyz"], [{"--unknown", nil}]}
iex> OptionParser.parse(
...> ["--limit", "3", "--unknown", "xyz"],
...> switches: [limit: :integer]
...> )
{[limit: 3, unknown: "xyz"], [], []}
iex> OptionParser.parse(
...> ["--unlock", "path/to/file", "--unlock", "path/to/another/file"],
...> strict: [unlock: :keep]
...> )
{[unlock: "path/to/file", unlock: "path/to/another/file"], [], []}
返回分隔符
分隔符 --
表示不再处理选项。默认情况下,分隔符不会作为参数的一部分返回,但这可以通过 :return_separator
选项更改
iex> OptionParser.parse(["--", "lib"], return_separator: true, strict: [])
{[], ["--", "lib"], []}
iex> OptionParser.parse(["--no-halt", "--", "lib"], return_separator: true, switches: [halt: :boolean])
{[halt: false], ["--", "lib"], []}
iex> OptionParser.parse(["script.exs", "--no-halt", "--", "foo"], return_separator: true, switches: [halt: :boolean])
{[{:halt, false}], ["script.exs", "--", "foo"], []}
与 parse/2
相同,但如果提供任何无效选项,则会引发 OptionParser.ParseError
异常。
如果没有错误,则返回一个 {parsed, rest}
元组,其中
示例
iex> OptionParser.parse!(["--debug", "path/to/file"], strict: [debug: :boolean])
{[debug: true], ["path/to/file"]}
iex> OptionParser.parse!(["--limit", "xyz"], strict: [limit: :integer])
** (OptionParser.ParseError) 1 error found!
--limit : Expected type integer, got "xyz"
iex> OptionParser.parse!(["--unknown", "xyz"], strict: [])
** (OptionParser.ParseError) 1 error found!
--unknown : Unknown option
iex> OptionParser.parse!(
...> ["-l", "xyz", "-f", "bar"],
...> switches: [limit: :integer, foo: :integer],
...> aliases: [l: :limit, f: :foo]
...> )
** (OptionParser.ParseError) 2 errors found!
-l : Expected type integer, got "xyz"
-f : Expected type integer, got "bar"
与 parse/2
类似,但只解析 argv
的头部;一旦找到非开关,它就会停止解析。
有关更多信息,请参阅 parse/2
。
示例
iex> OptionParser.parse_head(
...> ["--source", "lib", "test/enum_test.exs", "--verbose"],
...> switches: [source: :string, verbose: :boolean]
...> )
{[source: "lib"], ["test/enum_test.exs", "--verbose"], []}
iex> OptionParser.parse_head(
...> ["--verbose", "--source", "lib", "test/enum_test.exs", "--unlock"],
...> switches: [source: :string, verbose: :boolean, unlock: :boolean]
...> )
{[verbose: true, source: "lib"], ["test/enum_test.exs", "--unlock"], []}
与 parse_head/2
相同,但如果提供任何无效选项,则会引发 OptionParser.ParseError
异常。
如果没有错误,则返回一个 {parsed, rest}
元组,其中
parsed
是解析的开关列表(与parse_head/2
中相同)rest
是参数列表(与parse_head/2
中相同)
示例
iex> OptionParser.parse_head!(
...> ["--source", "lib", "path/to/file", "--verbose"],
...> switches: [source: :string, verbose: :boolean]
...> )
{[source: "lib"], ["path/to/file", "--verbose"]}
iex> OptionParser.parse_head!(
...> ["--number", "lib", "test/enum_test.exs", "--verbose"],
...> strict: [number: :integer]
...> )
** (OptionParser.ParseError) 1 error found!
--number : Expected type integer, got "lib"
iex> OptionParser.parse_head!(
...> ["--verbose", "--source", "lib", "test/enum_test.exs", "--unlock"],
...> strict: [verbose: :integer, source: :integer]
...> )
** (OptionParser.ParseError) 2 errors found!
--verbose : Missing argument of type integer
--source : Expected type integer, got "lib"
将字符串拆分为 argv/0
块。
此函数将给定的 string
拆分为字符串列表,方式类似于许多 shell。
示例
iex> OptionParser.split("foo bar")
["foo", "bar"]
iex> OptionParser.split("foo \"bar baz\"")
["foo", "bar baz"]
@spec to_argv(Enumerable.t(), options()) :: argv()
接收键值可枚举并将其转换为 argv/0
.
键必须是原子。具有 nil
值的键将被丢弃,布尔值将转换为 --key
或 --no-key
(如果值分别为 true
或 false
),所有其他值都将使用 to_string/1
进行转换。
建议将与 parse/2
传递的相同 options
集传递给 to_argv/2
。某些开关只有在拥有 :switches
信息的情况下才能被正确重建。
示例
iex> OptionParser.to_argv(foo_bar: "baz")
["--foo-bar", "baz"]
iex> OptionParser.to_argv(bool: true, bool: false, discarded: nil)
["--bool", "--no-bool"]
某些开关将根据开关类型输出不同的值
iex> OptionParser.to_argv([number: 2], switches: [])
["--number", "2"]
iex> OptionParser.to_argv([number: 2], switches: [number: :count])
["--number", "--number"]