System.CommandLine 的命令行语法概述

重要

System.CommandLine 目前为预览版,本文档适用于版本 2.0 beta 4。 一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。

本文介绍了 System.CommandLine 可识别的命令行语法。 这些信息对于 .NET 命令行应用(包括 .NET CLI)的用户和开发人员非常有用。

令牌

System.CommandLine 将命令行输入分析为令牌,这些令牌是以空格分隔的字符串。 例如,请考虑以下命令行:

dotnet tool install dotnet-suggest --global --verbosity quiet

此输入由 dotnet 应用程序分析为令牌 toolinstalldotnet-suggest--global--verbosityquiet

令牌会解释为命令、选项或自变量。 当前调用的命令行应用会确定如何解释第一个令牌之后的令牌。 下表显示了 System.CommandLine 如何解释前面的示例:

令牌 分析为
tool 子命令
install 子命令
dotnet-suggest install 命令的自变量
--global install 命令的选项
--verbosity install 命令的选项
quiet --verbosity 选项的自变量

如果令牌括在引号 (") 中,则可以包含空格。 下面是一个示例:

dotnet tool search "ef migrations add"

命令

命令行输入中的命令是令牌,用于指定操作或定义一组相关操作。 例如:

  • dotnet run 中,run 是指定操作的命令。
  • dotnet tool install 中,install 是指定操作的命令,tool 是指定一组相关命令的命令。 还有其他与工具相关的命令,例如 tool uninstalltool listtool update

根命令

根命令是用于指定应用可执行文件的名称的命令。 例如,dotnet 命令用于指定 dotnet.exe 可执行文件。

子命令

大多数命令行应用都支持子命令,也称为“谓词”。 例如,dotnet 命令具有通过输入 dotnet run 进行调用的 run 子命令。

子命令可以有自己的子命令。 在 dotnet tool install 中,installtool 的子命令。

选项

选项是可传递给命令的命名参数。 POSIX CLI 通常以两个连字符 (--) 作为选项名称的前缀。 下面的示例显示了两个选项:

dotnet tool update dotnet-suggest --verbosity quiet --global
                                  ^---------^       ^------^

如此示例所示,选项的值可以是显式的(--verbosityquiet),也可以是隐式的(--global 后面没有任何内容)。 如果在命令行上指定了选项,没有指定值的选项通常是默认为 true 的布尔参数。

对于某些 Windows 命令行应用,需要在选项名称中使用斜杠 (/) 来标识选项。 例如:

msbuild /version
        ^------^

System.CommandLine 支持 POSIX 和 Windows 前缀约定。 在配置选项时,应指定选项名称,包括前缀。

参数

自变量是传递给选项或命令的值。 以下示例显示了 verbosity 选项的自变量和 build 命令的自变量。

dotnet tool update dotnet-suggest --verbosity quiet --global
                                              ^---^
dotnet build myapp.csproj
             ^----------^

如果未显式提供自变量,则自变量可以具有适用的默认值。 例如,当选项名称位于命令行中时,许多选项都是具有默认值 true 的隐式布尔参数。 以下命令行示例是等效的:

dotnet tool update dotnet-suggest --global
                                  ^------^

dotnet tool update dotnet-suggest --global true
                                  ^-----------^

某些选项具有必需的自变量。 例如,在 .NET CLI 中,--output 需要文件夹名称自变量。 如果未提供该自变量,则命令将失败。

自变量可以具有预期类型,如果自变量无法分析为预期类型,则 System.CommandLine 会显示错误消息。 例如,以下命令出错是因为“silent”不是 --verbosity 的有效值之一:

dotnet build --verbosity silent
Cannot parse argument 'silent' for option '-v' as expected type 'Microsoft.DotNet.Cli.VerbosityOptions'. Did you mean one of the following?
Detailed
Diagnostic
Minimal
Normal
Quiet

对于可以提供多少个值,自变量也是有预期的。 有关自变量 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 不支持自动别名。

事例敏感性

根据 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 Max 示例有效性 示例
0 0 有效: --file
无效: --file a.json
无效: --file a.json --file b.json
0 1 有效: --flag
有效: --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。 例如,int 选项的 arity 为 ExactlyOneList<int> 选项的 arity 为 OneOrMore

选项替代

如果 arity 最大值为 1,则 System.CommandLine 仍可配置为接受选项的多个实例。 在这种情况下,重复选项的最后一个实例将覆盖任何较早的实例。 在下面的示例中,值 2 将传递给 myapp 命令。

myapp --delay 3 --message example --delay 2

多个参数

如果 arity 最大值大于 1,System.CommandLine 可以配置为接受一个选项有多个自变量而不重复选项名称。

在下面的示例中,传递给 myapp 命令的列表将包含“a”、“b”、“c”和“d”:

myapp --list a b c --list d

选项捆绑

POSIX 建议支持捆绑单字符选项(也称为“堆叠”)。 捆绑选项是单个连字符前缀后一起指定的单字符选项别名。 只有最后一个选项可以指定自变量。 例如,以下命令行是等效的:

git clean -f -d -x
git clean -fdx

如果在选项捆绑后提供了自变量,则该自变量适用于捆绑中的最后一个选项。 以下命令行是等效的:

myapp -a -b -c arg
myapp -abc arg

在此示例的两个变体中,自变量 arg 将仅适用于选项 -c

布尔选项(标记)

如果为具有 bool 自变量的选项传递了 truefalse,则它会像预期的那样进行分析。 但是,自变量类型为 bool 的选项通常不需要指定自变量。 布尔选项(有时称为“标记”)的 arity 通常为 ZeroOrOne。 如果命令行上有选项名称,但后面没有自变量,则产生默认值 true。 命令行输入中缺少选项名称会产生 false 值。 如果 myapp 命令输出名为 --interactive 的布尔选项的值,则以下输入将产生以下输出:

myapp
myapp --interactive
myapp --interactive false
myapp --interactive true
False
True
False
True

--help 选项

命令行应用通常会提供一个选项来显示可用命令、选项和自变量的简要说明。 System.CommandLine 会自动生成帮助输出。 例如:

dotnet list --help
Description:
  List references or packages of a .NET project.

Usage:
  dotnet [options] list [<PROJECT | SOLUTION>] [command]

Arguments:
  <PROJECT | SOLUTION>  The project or solution file to operate on. If a file is not specified, the command will search the current directory for one.

Options:
  -?, -h, --help  Show command line help.

Commands:
  package    List all package references of the project or solution.
  reference  List all project-to-project references of the project.

应用用户可能习惯使用不同方式在不同平台上请求帮助,因此,基于 System.CommandLine 构建的应用会对多种请求帮助的方式做出响应。 以下命令都是等效的:

dotnet --help
dotnet -h
dotnet /h
dotnet -?
dotnet /?

帮助输出不一定显示所有可用的命令、自变量和选项。 其中一些可能是隐藏的,这意味着它们不会显示在帮助输出中,但可以在命令行上指定。

--version 选项

基于 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

下面介绍了语法规则,它们决定了响应文件中文本的解释方式:

  • 标记由空格分隔。 包含 Good morning! 的行将被视为两个标记:Good 和 morning!
  • 括在引号中的多个标记将被解释为单个标记。 包含 "Good morning!" 的行将被视为单个标记 Good morning!
  • # 符号与行尾之间的任何文本都被视为注释并忽略。
  • 前缀为 @ 的标记可以引用其他响应文件。
  • 响应文件可以包含多行文本。 这些行是串接的,并被解释为一系列标记。

指令

System.CommandLine 引入了一个称为“指令”的语法元素。 例如 [parse] 指令。 在应用名称后面添加 [parse] 后,System.CommandLine 将显示分析结果的关系图,而不是调用命令行应用:

dotnet [parse] build --no-restore --output ./build-output/
       ^-----^
[ dotnet [ build [ --no-restore <True> ] [ --output <./build-output/> ] ] ]

指令的用途是提供可跨命令行应用程序应用的横切功能。 由于指令在语法上不同于应用自己的语法,因此它们可以提供在整个应用中适用的功能。

指令必须符合以下语法规则:

  • 它是命令行上位于应用之后但在任何子命令或选项之前的一个令牌。
  • 括在方括号中。
  • 不包含空格。

无法识别的指令将被忽略,而不会导致分析错误。

指令可以包含自变量,该自变量与指令名称之间用英文冒号隔开。

以下指令是内置的:

[parse] 指令

用户和开发人员可能会发现,查看应用如何解释给定输入会很有用。 System.CommandLine 应用的默认功能之一是 [parse] 指令,该指令允许你预览分析命令输入的结果。 例如:

myapp [parse] --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> ]! 表示分析错误。 int 选项的值 not-an-int 无法分析为预期类型。 该错误也可以在包含错误选项的命令前面通过 ! 来标记:![ myapp...
  • 对于选项结果 *[ --fgcolor <White> ],未在命令行中指定选项,因此使用了配置的默认值。 White 是此选项的有效值。 星号表示值为默认值。
  • ???--> 指向与应用的任何命令或选项都不匹配的输入。

[suggest] 指令

[suggest] 指令允许你在不知道确切命令时搜索命令。

dotnet [suggest] buil
build
build-server
msbuild

设计指南

以下各部分提供了在设计 CLI 时建议遵循的指导原则。 将你的应用在命令行上的预期行为想象成与 REST API 服务器在 URL 中的预期行为类似。 REST API 的一致规则使它们随时可供客户端应用程序开发人员使用。 同样,如果 CLI 设计遵循通用的模式,则命令行应用程序的用户将获得更好的体验。

CLI 一旦创建,就很难更改,尤其是当你的用户已经在想要一直运行的脚本中使用 CLI 时。 此处的准则是在 .NET CLI 发布后开发的,因此 .NET CLI 并不总是遵循这些准则。 我们正在更新 .NET CLI,以便在不引入重大更改的情况下遵循这些准则。 此项工作的一个示例是 .NET 7 中 dotnet new 的新设计。

命令和子命令

如果某个命令具有子命令,则该命令应用作一个区域或子命令的分组标识符,而不是指定一个操作。 在调用应用时,应指定分组命令和其中一个子命令。 例如,尝试运行 dotnet tool,你会收到错误消息,因为 tool 命令仅标识了一组与工具相关的子命令,例如 installlist。 你可以运行 dotnet tool install,但 dotnet tool 本身可能是不完整的。

有一种定义区域的方法可以帮到你的用户,那就是整理帮助输出。

在 CLI 中,通常有一个隐式区域。 例如,在 .NET CLI 中,隐式区域是项目,在 Docker CLI 中,隐式区域是映像。 因此,可以在不包括区域的情况下使用 dotnet build。 请考虑你的 CLI 是否有隐式区域。 如果有,请考虑是否允许用户根据需要包括或忽略它,如 docker builddocker image build 中所示。 如果你选择允许用户键入隐式区域,则对于这组命令,你还会自动获得帮助和 Tab 键补全功能。 通过定义两个执行相同操作的命令,提供隐式组的可选用法。

作为参数的选项

选项应为命令提供参数,而不是指定操作本身。 这是一种建议的设计原则,但 System.CommandLine 并不总是遵循此规则(--help 用于显示帮助信息)。

短格式别名

通常,我们建议你尽可能减少定义的短格式选项别名的数量。

尤其是避免以不同于 .NET CLI 和其他 .NET 命令行应用程序中的常见用法的方式使用以下任何别名:

  • -i(对于 --interactive)。

    此选项会告知用户,他们可能会收到提示,让其输入命令需要回答的问题。 例如,提示输入用户名。 你的 CLI 可以在脚本中使用,因此在提示未指定此开关的用户时要特别谨慎。

  • -o(对于 --output)。

    某些命令在执行时会生成文件。 应使用此选项来帮助确定这些文件所在的位置。 如果创建了单个文件,则此选项应为文件路径。 如果创建了多个文件,则此选项应为目录路径。

  • -v(对于 --verbosity)。

    命令通常在控制台中向用户提供输出;此选项用于指定用户请求的输出量。 有关详细信息,请参阅本文后面的 --verbosity 选项

此外,还有一些别名的常见用法仅限于 .NET CLI。 你可以在应用中将这些别名用于其他选项,但请注意可能会造成混淆。

  • --configuration,表示集 -c

    此选项通常是指命名的生成配置,如 DebugRelease。 你可以为配置使用所希望的任何名称,但大多数工具都希望使用其中一个名称。 此设置通常用于以对该配置有意义的方式配置其他属性,例如,在生成 Debug 配置时执行较少的代码优化。 如果你的命令具有不同的操作模式,请考虑此选项。

  • --framework,表示集 -f

    此选项用于选择要执行的单个目标框架名字对象 (TFM),因此,如果你的 CLI 应用程序根据所选择的 TFM 而有不同的行为,则应支持此标记。

  • --property,表示集 -p

    如果应用程序最终会调用 MSBuild,则用户通常需要以某种方式自定义该调用。 此选项允许在命令行上使用 MSBuild 属性,并将其传递给基础 MSBuild 调用。 如果你的应用不使用 MSBuild 但需要一组键值对,则请考虑使用此相同选项名称来满足用户的期望。

  • --runtime,表示集 -r

    如果你的应用程序可以在不同运行时上运行,或者具有特定于运行时的逻辑,请考虑支持此选项,作为指定运行时标识符的方法。 如果你的应用支持 --runtime,请考虑支持 --os--arch。 通过这些选项,可以只指定 RID 的操作系统或体系结构部分,将未指定的部分留给当前平台来确定。 有关详细信息,请查看 dotnet publish

短名称

设置命令、选项和自变量的名称时应尽可能简短且易于拼写。 例如,如果 class 足够清楚,则不要使用命令 classification

小写名称

仅以小写形式定义名称,但可以创建大写别名,使命令或选项不区分大小写。

小写短横线式名称

使用小写短横线格式来区分词语。 例如,--additional-probing-path

复数形式

在应用中,单复数形式要保持一致。 例如,不要为可具有多个值(最大 arity 大于 1)的选项混合使用复数和单数名称:

选项名称 一致性
--additional-probing-paths--sources
--additional-probing-path--source
--additional-probing-paths--source
--additional-probing-path--sources

谓词与名词

对于表示操作的命令,请使用谓词而不是名词,例如:dotnet workload remove,而不是 dotnet workload removal。 对于选项,请使用名词而不是谓词,例如:--configuration,而不是 --configure

--verbosity 选项

System.CommandLine 应用程序通常会提供一个 --verbosity 选项,用于指定发送到控制台的输出量。 下面是五个标准设置:

  • Q[uiet]
  • M[inimal]
  • N[ormal]
  • D[etailed]
  • Diag[nostic]

这些是标准名称,但现有应用有时会使用 Silent(代替 Quiet)、TraceDebugVerbose(代替 Diagnostic)。

每个应用都会定义自己的条件,用于确定每个级别显示的内容。 通常,应用只需要三个级别:

  • 无提示
  • 普通
  • 诊断

如果应用不需要五个不同的级别,选项仍应定义这五个设置。 在这种情况下,MinimalNormal 将生成相同的输出,DetailedDiagnostic 将生成相同的输出。 这样,用户就可以使用最合适的方式键入熟悉的内容。

Quiet 的预期行为是不在控制台上显示任何输出。 但是,如果应用提供了交互模式,则应用应执行以下替代方法之一:

  • 指定 --interactive 时显示输入提示,即使 --verbosityQuiet 也是如此。
  • 禁止同时使用 --verbosity Quiet--interactive

否则,应用将等待输入,而不会告知用户它在等待什么。 应用程序看上去已经冻结,而用户不知道应用程序正在等待输入。

如果要定义别名,请使用 -v 来表示 --verbosity,并采用无自变量的 -v 作为 --verbosity Diagnostic 的别名。 使用 -q 来表示 --verbosity Quiet

.NET CLI 和 POSIX 约定

.NET CLI 并没有始终如一地遵循所有 POSIX 约定。

双短划线

.NET CLI 中有多个命令具有双短划线令牌的特殊实现。 对于 dotnet rundotnet watchdotnet tool run-- 后面的令牌会传递到命令正在运行的应用。 例如:

dotnet run --project ./myapp.csproj -- --message "Hello world!"
                                    ^^

在此示例中,--project 选项将传递到 dotnet run 命令,并将带有自变量的 --message 选项作为命令行选项传递给正在运行的 myapp。

将选项传递给通过使用 dotnet run 运行的应用时,不一定始终需要 -- 令牌。 如果没有双短划线,dotnet run 命令会自动将未识别为应用到 dotnet run 自身或 MSBuild 的选项传递给正在运行的应用。 因此,以下命令行是等效的,因为 dotnet run 无法识别自变量和选项:

dotnet run -- quotes read --delay 0 --fg-color red
dotnet run quotes read --delay 0 --fg-color red

省略选项-自变量分隔符

.NET CLI 不支持允许在指定单字符选项别名时省略分隔符的 POSIX 约定。

在不重复选项名称的情况下允许多个自变量

.NET CLI 不接受一个选项在不重复选项名称的情况下有多个自变量。

布尔选项

在 .NET CLI 中,某些布尔值选项在传递 false 时将与传递 true 时产生相同的行为。 当实现选项的 .NET CLI 代码仅检查是否存在该选项时,将会出现此行为,同时将忽略值。 例如,dotnet build 命令的 --no-restore。 传递 no-restore false 将跳过还原操作,就像指定 no-restore trueno-restore 时一样。

小写短横线格式

在某些情况下,.NET CLI 不会对命令、选项或自变量名称使用小写短横线格式。 例如,有一个 .NET CLI 选项,名为 --additionalprobingpath,而不是 --additional-probing-path

另请参阅