Como definir comandos, opções e argumentos em System.CommandLine
Importante
System.CommandLine
está atualmente em PREVIEW, e esta documentação é para a versão 2.0 beta 4.
Algumas informações estão relacionadas ao produto de pré-lançamento que pode ser substancialmente modificado antes de ser lançado. A Microsoft não faz garantias, de forma expressa ou implícita, em relação à informação aqui apresentada.
Este artigo explica como definir comandos, opções e argumentos em aplicativos de linha de comando criados com a System.CommandLine
biblioteca. Para criar um aplicativo completo que ilustre essas técnicas, consulte o tutorial Introdução ao System.CommandLine.
Para obter orientação sobre como criar comandos, opções e argumentos de um aplicativo de linha de comando, consulte Diretrizes de design.
Definir um comando raiz
Cada aplicativo de linha de comando tem um comando raiz, que se refere ao próprio arquivo executável. O caso mais simples para invocar seu código, se você tiver um aplicativo sem subcomandos, opções ou argumentos, ficaria assim:
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);
}
}
Definir subcomandos
Os comandos podem ter comandos filho, conhecidos como subcomandos ou verbos, e podem aninhar quantos níveis você precisar. Você pode adicionar subcomandos conforme mostrado no exemplo a seguir:
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);
O subcomando mais interno neste exemplo pode ser invocado assim:
myapp sub1 sub1a
Definir opções
Um método manipulador de comandos normalmente tem parâmetros, e os valores podem vir de opções de linha de comando. O exemplo a seguir cria duas opções e as adiciona ao comando root. Os nomes das opções incluem prefixos de hífen duplo, o que é típico das CLIs POSIX. O código do manipulador de comandos exibe os valores dessas opções:
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);
Aqui está um exemplo de entrada de linha de comando e a saída resultante para o código de exemplo anterior:
myapp --delay 21 --message "Hello world!"
--delay = 21
--message = Hello world!
Opções globais
Para adicionar uma opção a um comando de cada vez, use o Add
método ou AddOption
como mostrado no exemplo anterior. Para adicionar uma opção a um comando e recursivamente a todos os seus subcomandos, use o AddGlobalOption
método, conforme mostrado no exemplo a seguir:
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);
O código anterior é adicionado --delay
como uma opção global ao comando raiz e está disponível no manipulador para subCommand1a
.
Definir argumentos
Os argumentos são definidos e adicionados a comandos como opções. O exemplo a seguir é como o exemplo de opções, mas define argumentos em vez de opções:
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);
Aqui está um exemplo de entrada de linha de comando e a saída resultante para o código de exemplo anterior:
myapp 42 "Hello world!"
<delay> argument = 42
<message> argument = Hello world!
Um argumento que é definido sem um valor padrão, como messageArgument
no exemplo anterior, é tratado como um argumento necessário. Uma mensagem de erro é exibida e o manipulador de comandos não é chamado, se um argumento necessário não for fornecido.
Definir aliases
Ambos os comandos e opções suportam aliases. Você pode adicionar um alias a uma opção chamando AddAlias
:
var option = new Option("--framework");
option.AddAlias("-f");
Dado esse alias, as seguintes linhas de comando são equivalentes:
myapp -f net6.0
myapp --framework net6.0
Os aliases de comando funcionam da mesma maneira.
var command = new Command("serialize");
command.AddAlias("serialise");
Esse código torna equivalentes as seguintes linhas de comando:
myapp serialize
myapp serialise
Recomendamos que você minimize o número de aliases de opção definidos e evite definir determinados aliases em particular. Para obter mais informações, consulte Aliases de formulário curto.
Opções necessárias
Para tornar uma opção necessária, defina sua IsRequired
propriedade como true
, conforme mostrado no exemplo a seguir:
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);
A seção de opções da ajuda do comando indica que a opção é necessária:
Options:
--endpoint <uri> (REQUIRED)
--version Show version information
-?, -h, --help Show help and usage information
Se a linha de comando deste aplicativo de exemplo não incluir --endpoint
, uma mensagem de erro será exibida e o manipulador de comandos não será chamado:
Option '--endpoint' is required.
Se uma opção necessária tiver um valor padrão, a opção não precisa ser especificada na linha de comando. Nesse caso, o valor padrão fornece o valor de opção necessário.
Comandos, opções e argumentos ocultos
Talvez você queira oferecer suporte a um comando, opção ou argumento, mas evite facilitar a descoberta. Por exemplo, pode ser um recurso preterido, administrativo ou de visualização. Use a IsHidden propriedade para impedir que os usuários descubram esses recursos usando o preenchimento de guias ou a ajuda, conforme mostrado no exemplo a seguir:
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);
A seção options da ajuda de comando deste exemplo omite a --endpoint
opção.
Options:
--version Show version information
-?, -h, --help Show help and usage information
Definir aridade de argumento
Você pode definir explicitamente a aridade do argumento usando a Arity
propriedade, mas na maioria dos casos isso não é necessário. System.CommandLine
determina automaticamente a aridade do argumento com base no tipo de argumento:
Tipo de argumento | Aridade padrão |
---|---|
Boolean |
ArgumentArity.ZeroOrOne |
Tipos de recolha | ArgumentArity.ZeroOrMore |
Tudo o resto | ArgumentArity.ExactlyOne |
Múltiplos argumentos
Por padrão, quando você chama um comando, pode repetir um nome de opção para especificar vários argumentos para uma opção que tenha aridade máxima maior que um.
myapp --items one --items two --items three
Para permitir vários argumentos sem repetir o nome da opção, defina Option.AllowMultipleArgumentsPerToken como true
. Essa configuração permite que você insira a seguinte linha de comando.
myapp --items one two three
A mesma configuração tem um efeito diferente se a aridade máxima do argumento for 1. Ele permite que você repita uma opção, mas leva apenas o último valor na linha. No exemplo a seguir, o valor three
seria passado para o aplicativo.
myapp --item one --item two --item three
Listar valores de argumento válidos
Para especificar uma lista de valores válidos para uma opção ou argumento, especifique um enum como o tipo de opção ou use FromAmong, conforme mostrado no exemplo a seguir:
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");
Aqui está um exemplo de entrada de linha de comando e a saída resultante para o código de exemplo anterior:
myapp --language not-a-language
Argument 'not-a-language' not recognized. Must be one of:
'csharp'
'fsharp'
'vb'
'pwsh'
'sql'
A seção de opções da ajuda do comando mostra os valores válidos:
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
Validação de opção e argumento
Para obter informações sobre validação de argumentos e como personalizá-la, consulte as seguintes seções no artigo Vinculação de parâmetros: