如何在 System.CommandLine 中定義命令、選項和引數
重要
System.CommandLine
目前為預覽版,而此文件適用於版本 2.0 搶鮮版 (Beta) 4。
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
本文說明如何在使用 System.CommandLine
程式庫建置的命令列應用程式中,定義命令、選項和引數。 若要建置完整的應用程式來說明這些技術,請參閱開始使用 System.CommandLine教學課程。
如需有關如何設計命令列應用程式命令、選項和引數的指引,請參閱設計指引。
定義根命令
每個命令列應用程式都有一個參考可執行檔本身的根命令。 如果您有一個不含子命令、選項或引數的應用程式,叫用程式碼的最簡單案例會如下所示:
using System.CommandLine;
class Program
{
static async Task Main(string[] args)
{
var rootCommand = new RootCommand("Sample command-line app");
rootCommand.SetHandler(() =>
{
Console.WriteLine("Hello world!");
});
await rootCommand.InvokeAsync(args);
}
}
定義子命令
命令可以有稱為「子命令」或「動詞」的下層命令,而且可以視需要巢狀多個層級。 您可以新增子命令,如下列範例所示:
var rootCommand = new RootCommand();
var sub1Command = new Command("sub1", "First-level subcommand");
rootCommand.Add(sub1Command);
var sub1aCommand = new Command("sub1a", "Second level subcommand");
sub1Command.Add(sub1aCommand);
此範例中最內部的子命令可以透過類似如下的方式叫用:
myapp sub1 sub1a
定義選項
命令處理常式方法通常具有參數,而且其值可能來自命令列選項。 下列範例會建立兩個選項,並將其新增至根命令。 選項名稱包含雙連字號前置詞,這在 POSIX CLI 中很常見。 命令處理常式程式碼會顯示這些選項的值:
var delayOption = new Option<int>
(name: "--delay",
description: "An option whose argument is parsed as an int.",
getDefaultValue: () => 42);
var messageOption = new Option<string>
("--message", "An option whose argument is parsed as a string.");
var rootCommand = new RootCommand();
rootCommand.Add(delayOption);
rootCommand.Add(messageOption);
rootCommand.SetHandler((delayOptionValue, messageOptionValue) =>
{
Console.WriteLine($"--delay = {delayOptionValue}");
Console.WriteLine($"--message = {messageOptionValue}");
},
delayOption, messageOption);
以下示範上述範例程式碼中的命令列輸入,以及產生的輸出:
myapp --delay 21 --message "Hello world!"
--delay = 21
--message = Hello world!
全域選項
若要將選項一次新增至一個命令,請使用 Add
或 AddOption
方法,如上述範例所示。 若要將選項新增至命令,並以遞迴方式新增至其所有子命令,請使用 AddGlobalOption
方法,如下列範例所示:
var delayOption = new Option<int>
("--delay", "An option whose argument is parsed as an int.");
var messageOption = new Option<string>
("--message", "An option whose argument is parsed as a string.");
var rootCommand = new RootCommand();
rootCommand.AddGlobalOption(delayOption);
rootCommand.Add(messageOption);
var subCommand1 = new Command("sub1", "First level subcommand");
rootCommand.Add(subCommand1);
var subCommand1a = new Command("sub1a", "Second level subcommand");
subCommand1.Add(subCommand1a);
subCommand1a.SetHandler((delayOptionValue) =>
{
Console.WriteLine($"--delay = {delayOptionValue}");
},
delayOption);
await rootCommand.InvokeAsync(args);
上述程式碼會將 --delay
新增為根命令的全域選項,而且可在 subCommand1a
的處理常式中使用。
定義引數
引數會定義並新增至選項之類的命令。 下列範例類似於選項範例,但會定義引數而非選項:
var delayArgument = new Argument<int>
(name: "delay",
description: "An argument that is parsed as an int.",
getDefaultValue: () => 42);
var messageArgument = new Argument<string>
("message", "An argument that is parsed as a string.");
var rootCommand = new RootCommand();
rootCommand.Add(delayArgument);
rootCommand.Add(messageArgument);
rootCommand.SetHandler((delayArgumentValue, messageArgumentValue) =>
{
Console.WriteLine($"<delay> argument = {delayArgumentValue}");
Console.WriteLine($"<message> argument = {messageArgumentValue}");
},
delayArgument, messageArgument);
await rootCommand.InvokeAsync(args);
以下示範上述範例程式碼中的命令列輸入,以及產生的輸出:
myapp 42 "Hello world!"
<delay> argument = 42
<message> argument = Hello world!
未定義預設值的引數 (例如上述範例中的 messageArgument
) 會被視為必要引數。 如果未提供必要引數,則會顯示錯誤訊息,而且不會呼叫命令處理常式。
定義別名
命令和選項都支援別名。 您可以呼叫 AddAlias
,將別名新增至選項:
var option = new Option("--framework");
option.AddAlias("-f");
如果提供此別名,則下列命令列會相等:
myapp -f net6.0
myapp --framework net6.0
命令別名的運作方式相同。
var command = new Command("serialize");
command.AddAlias("serialise");
此程式碼會讓下列命令列相等:
myapp serialize
myapp serialise
建議您盡可能將定義的選項別名數目減到最少,並避免特別定義特定別名。 如需詳細資訊,請參閱簡短格式別名。
必要選項
若要讓選項成為必要,請將其 IsRequired
屬性設定為 true
,如下列範例所示:
var endpointOption = new Option<Uri>("--endpoint") { IsRequired = true };
var command = new RootCommand();
command.Add(endpointOption);
command.SetHandler((uri) =>
{
Console.WriteLine(uri?.GetType());
Console.WriteLine(uri?.ToString());
},
endpointOption);
await command.InvokeAsync(args);
命令說明的選項區段指出選項為必要:
Options:
--endpoint <uri> (REQUIRED)
--version Show version information
-?, -h, --help Show help and usage information
如果此範例應用程式的命令列不包含 --endpoint
,則會顯示錯誤訊息,而且不會呼叫命令處理常式:
Option '--endpoint' is required.
如果必要選項具有預設值,則不需要在命令列上指定選項。 在此情況下,預設值會提供必要選項值。
隱藏命令、選項和引數
您可能既想支援命令、選項或引數,又想避免使用者輕易就能探索到這些項目。 例如,這可能是已被取代的功能、系統管理功能或預覽功能。 使用 IsHidden 屬性可防止使用者利用 TAB 鍵自動完成或說明來探索這類功能,如下列範例所示:
var endpointOption = new Option<Uri>("--endpoint") { IsHidden = true };
var command = new RootCommand();
command.Add(endpointOption);
command.SetHandler((uri) =>
{
Console.WriteLine(uri?.GetType());
Console.WriteLine(uri?.ToString());
},
endpointOption);
await command.InvokeAsync(args);
此範例命令說明的選項區段會省略 --endpoint
選項。
Options:
--version Show version information
-?, -h, --help Show help and usage information
設定引數元數
您可以使用 Arity
屬性來明確設定引數元數,但在大多數情況下並不需要。 System.CommandLine
會自動根據引數類型判斷引數元數:
引數類型 | 預設元數 |
---|---|
Boolean |
ArgumentArity.ZeroOrOne |
集合類型 | ArgumentArity.ZeroOrMore |
其他所有項目 | ArgumentArity.ExactlyOne |
多個引數
根據預設,當您呼叫命令時,您可以重複選項名稱,為最大元數大於一的選項指定多個引數。
myapp --items one --items two --items three
若要允許多個引數而不重複選項名稱,請將 Option.AllowMultipleArgumentsPerToken 設定為 true
。 此設定可讓您輸入下列命令列。
myapp --items one two three
如果最大引數元數為 1,則相同的設定會有不同的效果。 它可讓您重複選項,但只接受該行的最後一個值。 在下列範例中,會將值 three
傳遞至應用程式。
myapp --item one --item two --item three
列出有效的引數值
若要指定選項或引數的有效值清單,請將列舉指定為選項類型,或使用 FromAmong,如下列範例所示:
var languageOption = new Option<string>(
"--language",
"An option that that must be one of the values of a static list.")
.FromAmong(
"csharp",
"fsharp",
"vb",
"pwsh",
"sql");
以下示範上述範例程式碼中的命令列輸入,以及產生的輸出:
myapp --language not-a-language
Argument 'not-a-language' not recognized. Must be one of:
'csharp'
'fsharp'
'vb'
'pwsh'
'sql'
命令說明的選項區段會顯示有效值:
Options:
--language <csharp|fsharp|vb|pwsh|sql> An option that must be one of the values of a static list.
--version Show version information
-?, -h, --help Show help and usage information
選項和引數驗證
如需引數驗證及如何自訂的資訊,請參閱參數繫結一文中的下列各節: