重要
System.CommandLine
目前为预览版。 本文档适用于版本 2.0 beta 5。
某些信息与预发布产品有关,该产品可能在发布前进行大幅修改。 Microsoft对此处提供的信息不作任何明示或暗示的保证。
本文介绍可识别的 System.CommandLine
命令行语法。 此信息对 .NET 命令行应用(包括 .NET CLI)的用户和开发人员都很有用。
令牌
System.CommandLine
将命令行输入分析为标记,这些 标记是用空格分隔的字符串。 例如,请考虑以下命令行:
dotnet tool install dotnet-suggest --global --verbosity quiet
此输入由dotnet
应用程序分析为标记tool
、install
、dotnet-suggest
、--global
和--verbosity
quiet
。
令牌解释为命令、选项或参数。 当前调用的命令行应用会确定如何解释第一个令牌之后的令牌。 下表显示了如何 System.CommandLine
解释前面的示例:
令牌 | 分析为 |
---|---|
tool |
子命令 |
install |
子命令 |
dotnet-suggest |
安装命令的参数 |
--global |
安装命令的选项 |
--verbosity |
安装命令的选项 |
quiet |
--verbosity 选项的自变量 |
如果令牌括在引号 ("
) 中,则可以包含空格。 下面是一个示例:
dotnet tool search "ef migrations add"
指令
命令行输入中的 命令 是指定作或定义一组相关作的标记。 例如:
- 在
dotnet run
中,run
是一个指定动作的命令。 -
dotnet tool install
中,install
是一个指定动作的命令,而tool
是一个指定一组相关命令的命令。 还有其他与工具相关的命令,例如tool uninstall
,tool list
和tool update
。
Root命令
根命令是指定应用可执行文件的名称的命令。 例如, dotnet
该命令指定 dotnet.exe 可执行文件。
Command 是任何命令或子命令的常规用途类,而 RootCommand 是专用版本,适用于应用程序的根入口点。
RootCommand
继承所有功能 Command
,但添加了特定于根的行为和默认值,例如 “帮助”选项、 “版本”选项和 “建议”指令。
子命令
大多数命令行应用都支持 子命令,也称为 谓词。 例如,dotnet
命令具有通过输入 run
进行调用的 dotnet run
子命令。
子命令可以有自己的子命令。 在dotnet tool install
中,install
是tool
的一个子命令。
可以添加子命令,如以下示例所示:
RootCommand rootCommand = new();
Command sub1Command = new("sub1", "First-level subcommand");
rootCommand.Subcommands.Add(sub1Command);
Command sub1aCommand = new("sub1a", "Second level subcommand");
sub1Command.Subcommands.Add(sub1aCommand);
此示例中最内部的子命令可以调用如下:
myapp sub1 sub1a
选项
选项是可传递给命令的命名参数。
POSIX CLIs 通常为选项名称加上两个连字符(--
)。 以下示例显示了两个选项:
dotnet tool update dotnet-suggest --verbosity quiet --global
^---------^ ^------^
如本示例所示,选项的值可以是显式(quiet
对于 --verbosity
)或隐式(不遵循任何内容 --global
)。 没有指定值的选项通常是在命令行上指定选项时默认 true
的布尔参数。
对于某些 Windows 命令行应用,可以使用带选项名称的前导斜杠(/
)来标识选项。 例如:
msbuild /version
^------^
System.CommandLine
支持 POSIX 和 Windows 前缀约定。
配置选项时,请指定选项名称,包括前缀:
Option<int> delayOption = new("--delay", "-d")
{
Description = "An option whose argument is parsed as an int.",
DefaultValueFactory = parseResult => 42,
};
Option<string> messageOption = new("--message", "-m")
{
Description = "An option whose argument is parsed as a string."
};
RootCommand rootCommand = new();
rootCommand.Options.Add(delayOption);
rootCommand.Options.Add(messageOption);
若要向命令添加一个选项,并递归添加到其所有子命令,请使用该 System.CommandLine.Symbol.Recursive
属性。
必需选项
某些选项具有必需的自变量。 例如,在 .NET CLI 中, --output
需要文件夹名称参数。 如果未提供参数,该命令将失败。 若要使选项是必需的,请将其 Required 属性设置为 true
,如以下示例所示:
Option<FileInfo> fileOption = new("--output")
{
Required = true
};
如果所需选项具有默认值(通过 DefaultValueFactory 属性指定),则无需在命令行上指定该选项。 在这种情况下,默认值提供所需的选项值。
论据
参数是可以传递给命令的未命名参数。 以下示例演示命令的参数 build
。
dotnet build myapp.csproj
^----------^
配置参数时,可以指定参数名称(它不用于分析,但可用于按名称获取分析值或显示帮助)和类型:
Argument<int> delayArgument = new("delay")
{
Description = "An argument that is parsed as an int.",
DefaultValueFactory = parseResult => 42
};
Argument<string> messageArgument = new("message")
{
Description = "An argument that is parsed as a string."
};
RootCommand rootCommand = new();
rootCommand.Arguments.Add(delayArgument);
rootCommand.Arguments.Add(messageArgument);
默认值
如果未显式提供任何参数,则参数和选项可以具有适用的默认值。 例如,许多选项是隐式的布尔参数,默认情况下,当选项名称出现在命令行中时,其值为 true
。 以下命令行示例等效:
dotnet tool update dotnet-suggest --global
^------^
dotnet tool update dotnet-suggest --global true
^-----------^
在没有默认值的情况下定义的参数被视为必需参数。
分析错误
选项和参数具有预期类型,当无法分析值时,将生成错误。 例如,以下命令会出错,因为“静默”不是--verbosity
的有效值之一:
dotnet build --verbosity silent
Option<string> verbosityOption = new("--verbosity", "-v")
{
Description = "Set the verbosity level.",
};
verbosityOption.AcceptOnlyFromAmong("quiet", "minimal", "normal", "detailed", "diagnostic");
RootCommand rootCommand = new() { verbosityOption };
ParseResult parseResult = rootCommand.Parse(args);
foreach (ParseError parseError in parseResult.Errors)
{
Console.WriteLine(parseError.Message);
}
Argument 'silent' not recognized. Must be one of:
'quiet'
'minimal'
'normal'
'detailed'
'diagnostic'
对于可以提供多少个值,自变量也是有预期的。 有关自变量 arity 的部分中提供了相关示例。
选项和自变量的顺序
可以在命令行中先提供选项再提供参数,或先提供参数再提供选项。 以下命令等效:
dotnet add package System.CommandLine --prerelease
dotnet add package --prerelease System.CommandLine
可以按任意顺序指定选项。 以下命令等效:
dotnet add package System.CommandLine --prerelease --no-restore --source https://api.nuget.org/v3/index.json
dotnet add package System.CommandLine --source https://api.nuget.org/v3/index.json --no-restore --prerelease
当有多个参数时,顺序确实很重要。 以下命令不等效;它们因值的顺序而异,这可能会导致不同的结果:
myapp argument1 argument2
myapp argument2 argument1
别名
在 POSIX 和 Windows 中,某些命令和选项都有别名很常见。 这些通常是更易于键入的短形式。 别名还可用于其他目的,例如 模拟不区分大小写,并支持单词的多种拼写。
POSIX 短格式通常具有一个前导连字符,后跟一个字符。 以下命令等效:
dotnet build --verbosity quiet
dotnet build -v quiet
GNU 标准建议自动别名。 也就是说,您可以输入长格式命令或选项名称的任意部分,它会被接受。 此行为将使以下命令行等效:
dotnet publish --output ./publish
dotnet publish --outpu ./publish
dotnet publish --outp ./publish
dotnet publish --out ./publish
dotnet publish --ou ./publish
dotnet publish --o ./publish
System.CommandLine
不支持自动别名。 必须显式指定每个别名。 命令和选项都公开属性 Aliases
。
Option
具有接受别名作为参数的构造函数,因此可以在单个行中定义具有多个别名的选项:
Option<bool> helpOption = new("--help", ["-h", "/h", "-?", "/?"]);
Command command = new("serialize") { helpOption };
command.Aliases.Add("serialise");
建议尽量减少定义的选项别名数,并避免具体定义某些别名。 有关详细信息,请参阅 短格式别名。
事例敏感性
默认情况下,根据 POSIX 约定,命令和选项名称和别名区分大小写,并 System.CommandLine
遵循此约定。 如果你希望 CLI 不区分大小写,请为各种大小写备选项定义别名。 例如, --additional-probing-path
可能具有别名 --Additional-Probing-Path
和 --ADDITIONAL-PROBING-PATH
。
在某些命令行工具中,大小写上的差异会导致功能上的差异。 例如,git clean -X
的行为方式不同于 git clean -x
。 .NET CLI 全小写。
区分大小写不适用于基于枚举的选项的自变量值。 无论大小写如何,枚举名称都会匹配。
--
令牌
POSIX 约定会将双短划线 (--
) 令牌解释为转义机制。 双划线标记后面的所有内容都解释为命令的参数。 此功能可用于提交类似于选项的参数,因为它阻止将它们解释为选项。
假设 myapp 采用一个message
参数,并且希望其message
--interactive
值为 。 以下命令行可能会提供意外的结果。
myapp --interactive
如果myapp
没有--interactive
选项,--interactive
令牌将解释为参数。 但是,如果应用确实有一个选项 --interactive
,则此输入将解释为引用该选项。
以下命令行使用双划线标记将参数的值 message
设置为“--interactive”:
myapp -- --interactive
^^
System.CommandLine
支持此双短划线功能。
选项-自变量分隔符
System.CommandLine
允许使用空格、“=”或“:”作为选项名称与其参数之间的分隔符。 例如,以下命令等效:
dotnet build -v quiet
dotnet build -v=quiet
dotnet build -v:quiet
POSIX 约定允许在指定单字符选项别名时省略分隔符。 例如,以下命令等效:
myapp -vquiet
myapp -v quiet
System.CommandLine 默认情况下支持此语法。
自变量 arity
选项或命令参数的 arity 是指定该选项或命令时可以传递的值数。
Arity 以最小值和最大值表示,如下表所示:
Min | 麦克斯 | 示例有效性 | 示例: |
---|---|---|---|
0 | 0 | 有效: | --file |
无效: | --file a.json | ||
无效: | --file a.json --file b.json | ||
0 | 1 | 有效: | --标志 |
有效: | --flag true | ||
有效: | --flag false | ||
无效: | --flag false --flag false | ||
1 | 1 | 有效: | --file a.json |
无效: | --file | ||
无效: | --file a.json --file b.json | ||
0 | n | 有效: | --file |
有效: | --file a.json | ||
有效: | --file a.json --file b.json | ||
1 | n | 有效: | --file a.json |
有效: | --file a.json b.json | ||
无效: | --file |
System.CommandLine
使用 ArgumentArity 结构来定义 arity,具有以下值:
- Zero - 不允许任何值。
- ZeroOrOne - 可以有一个值或没有值。
- ExactlyOne - 必须有一个值。
- ZeroOrMore - 可以有一个值、多个值或没有值。
- OneOrMore - 可以有多个值;必须至少有一个值。
可以使用属性 Arity
显式设置 arity,但在大多数情况下不需要。
System.CommandLine
根据参数类型自动确定参数 Arity:
参数类型 | 默认 arity |
---|---|
Boolean |
ArgumentArity.ZeroOrOne |
集合类型 | ArgumentArity.ZeroOrMore |
其他 | ArgumentArity.ExactlyOne |
选项替代
如果 arity 最大值为 1, System.CommandLine
仍可配置为接受一个选项的多个实例。 在这种情况下,重复选项的最后一个实例将覆盖任何早期实例。 在以下示例中,值 2 将传递给 myapp
命令。
myapp --delay 3 --message example --delay 2
多个参数
默认情况下,调用命令时,可以重复选项名称,为具有大于一个最大 arity 的选项指定多个参数。
myapp --items one --items two --items three
若要允许多个参数而不重复选项名称,请设置为 AllowMultipleArgumentsPerTokentrue
。 此设置允许你输入以下命令行。
myapp --items one two three
如果最大参数 arity 为 1,则相同的设置将产生不同的效果。 它允许重复某个选项,但只采用行上的最后一个值。 在以下示例中,该值 three
将传递给应用。
myapp --item one --item two --item three
选项捆绑
POSIX 建议支持合并单字符选项,也称为叠加。 捆绑选项是单个连字符前缀后一起指定的单字符选项别名。 只有最后一个选项可以指定参数。 例如,以下命令行是等效的:
git clean -f -d -x
git clean -fdx
如果在选项捆绑后提供参数,则它适用于捆绑包中的最后一个选项。 以下命令行是等效的:
myapp -a -b -c arg
myapp -abc arg
在此示例中的这两个变体中,参数 arg
将仅适用于该选项 -c
。
布尔选项(标志)
如果为具有true
参数的选项传递false
或bool
,则会按预期对其进行分析。 参数类型为 bool
的选项通常不需要指定参数。 布尔选项(有时称为“标记”)的 arity 通常为 ZeroOrOne。 在命令行中,当选项名称出现时且其后没有参数,默认值为true
。 命令行输入中缺少选项名称会导致值为false
。
myapp
如果命令输出名为--interactive
布尔选项的值,则以下输入将创建以下输出:
myapp
myapp --interactive
myapp --interactive false
myapp --interactive true
False
True
False
True
版本选项
基于System.CommandLine
构建的应用会在使用与根命令一起使用的--version
选项时自动提供版本号。 例如:
dotnet --version
6.0.100
响应文件
响应文件是包含命令行应用的一组令牌的文件。 响应文件是System.CommandLine
的一项功能,在两种场景中非常有用:
- 通过指定超过终端字符限制的输入来调用命令行应用。
- 重复调用同一命令而无需重新输入整个行。
若要使用响应文件,请在要插入命令、选项和参数的行中输入以符号为前缀 @
的文件名。
.rsp 文件扩展名是一种常见的约定,但你可以使用任何文件扩展名。
以下行等效:
dotnet build --no-restore --output ./build-output/
dotnet @sample1.rsp
dotnet build @sample2.rsp --output ./build-output/
sample1.rsp 的内容:
build
--no-restore
--output
./build-output/
sample2.rsp 的内容:
--no-restore
以下是用于确定如何解释响应文件中文本的语法规则:
- 标记由空格分隔。 包含早安的线条被视为两个标记,“好”和“早上!”。
- 括在引号中的多个令牌被解释为单个标记。 包含“早安!”的行被视为一个标记,即早安!
- 符号和行尾之间的
#
任何文本都被视为注释并忽略。 - 以
@
为前缀的令牌可以引用其他响应文件。 - 响应文件可以包含多行文本。 这些行是串接的,并被解释为一系列标记。
指令
System.CommandLine
引入一个名为由类型表示的 指令 的 Directive 语法元素。 例如,该[diagram]
指令是内置指令。 在应用名称后面包含 [diagram]
时, System.CommandLine
显示分析结果的关系图,而不是调用命令行应用:
dotnet [diagram] build --no-restore --output ./build-output/
^-----^
[ dotnet [ build [ --no-restore <True> ] [ --output <./build-output/> ] ] ]
指令的目的是提供跨命令行应用可应用的交叉功能。 由于指令在语法上与应用自己的语法不同,因此它们可以提供跨应用的功能。
指令必须符合以下语法规则:
- 它是命令行上的令牌,该令牌位于应用的名称之后,但在任何子命令或选项之前。
- 它被括在方括号中。
- 它不包含空格。
忽略无法识别的指令,而不会导致分析错误。
指令可以包含一个参数,该参数与指令名称之间用冒号分隔。
以下指令是内置的:
[diagram]
指令
用户和开发人员都可能会发现,了解应用如何解释给定输入会很有用。 应用的默认功能 System.CommandLine
之一是 [diagram]
指令,它允许预览分析命令输入的结果。 例如:
myapp [diagram] --delay not-an-int --interactive --file filename.txt extra
![ myapp [ --delay !<not-an-int> ] [ --interactive <True> ] [ --file <filename.txt> ] *[ --fgcolor <White> ] ] ???--> extra
在上面的示例中:
- 命令(
myapp
)、其子选项以及这些选项的参数使用方括号进行分组。 - 对于选项结果
[ --delay !<not-an-int> ]
,!
表示解析错误。not-an-int
选项的值int
无法分析为预期类型。 该错误还通过!
标记在包含错误选项的命令之前:![ myapp...
。 - 对于选项结果
*[ --fgcolor <White> ]
,该选项未在命令行上指定,因此使用了配置的默认值。White
是此选项的有效值。 星号指示该值为默认值。 -
???-->
指向与应用的任何命令或选项不匹配的输入。
建议指令
该 [suggest]
指令允许在不知道确切命令时搜索命令。
dotnet [suggest] buil
build
build-server
msbuild