Como definir comandos, opções e argumentos em System.CommandLine
Importante
Atualmente, System.CommandLine
está em VERSÃO PRÉVIA, e essa documentação é para a versão 2.0 beta 4.
Algumas informações estão relacionadas a produtos de pré-lançamento que poderão ser substancialmente modificados antes do lançamento. A Microsoft não oferece garantias, expressas ou implícitas, das informações aqui fornecidas.
Este artigo explica como definir comandos, opções e argumentos em aplicativos de linha de comando criados com a biblioteca System.CommandLine
. Para criar um aplicativo completo que ilustra essas técnicas, confira o tutorial Introdução a System.CommandLine.
Para obter diretrizes sobre como criar comandos, opções e argumentos de um aplicativo de linha de comando, confira as 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, terá esta aparência:
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 filhos, conhecidos como subcomandos ou verbos, e eles podem aninhar quantos níveis você precisar. Você pode adicionar subcomandos como mostrado neste exemplo:
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 da seguinte maneira:
myapp sub1 sub1a
Definir opções
Um método de manipulador de comando 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 raiz. Os nomes de opção incluem prefixos de hifen duplo, que é típico para CLIs POSIX. O código do manipulador de comando 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 do 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 por vez, use o método Add
ou AddOption
, conforme mostrado no exemplo anterior. Para adicionar uma opção a um comando e recursivamente a todos os seus subcomandos, use o método AddGlobalOption
, 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 adiciona --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 aos 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 do código de exemplo anterior:
myapp 42 "Hello world!"
<delay> argument = 42
<message> argument = Hello world!
Um argumento definido sem um valor padrão, como messageArgument
no exemplo anterior, é tratado como um argumento obrigatório. Uma mensagem de erro é exibida, e o manipulador de comandos não é chamado, se um argumento obrigatório não é fornecido.
Definir aliases
Comandos e opções dão suporte para aliases. Você pode adicionar um alias a uma opção chamando AddAlias
:
var option = new Option("--framework");
option.AddAlias("-f");
Com 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 as seguintes linhas de comando equivalentes:
myapp serialize
myapp serialise
Recomendamos que você minimize o número de aliases de opção definidos e evite definir determinados aliases específicos. Para obter mais informações, confira Aliases de forma abreviada.
Opções obrigatórias
Para tornar uma opção obrigatória, defina a propriedade IsRequired
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 de comando indica que a opção é obrigatória:
Options:
--endpoint <uri> (REQUIRED)
--version Show version information
-?, -h, --help Show help and usage information
Se a linha de comando do aplicativo de exemplo não incluir --endpoint
, uma mensagem de erro será exibida e o manipulador de comando não será chamado:
Option '--endpoint' is required.
Se uma opção obrigatória tiver um valor padrão, ela não precisará ser especificada na linha de comando. Nesse caso, o valor padrão fornecerá o valor da opção obrigatória.
Comandos, opções e argumentos ocultos
Talvez você queira dar suporte a um comando, opção ou argumento, mas evitar facilitar a descoberta. Por exemplo, pode ser um recurso preterido, administrativo ou de versão prévia. Use a propriedade IsHidden para evitar que os usuários descubram esses recursos usando a conclusão da guia 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 de opções do comando deste exemplo ajuda a omitir a opção --endpoint
.
Options:
--version Show version information
-?, -h, --help Show help and usage information
Definir arity de argumento
Você pode definir explicitamente a arity do argumento usando a propriedade Arity
. Mas, na maioria dos casos, isso não é necessário. System.CommandLine
determina automaticamente a arity do argumento com base no tipo dele:
Tipo de argumento | Arity padrão |
---|---|
Boolean |
ArgumentArity.ZeroOrOne |
Tipos de coleção | ArgumentArity.ZeroOrMore |
Todo o resto | ArgumentArity.ExactlyOne |
Vários argumentos
Por padrão, ao chamar um comando, você pode repetir um nome de opção para especificar vários argumentos para uma opção que tenha arity 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 linha de comando a seguir.
myapp --items one two three
A mesma configuração terá um efeito diferente se a arity máxima do argumento for 1. Ela permite que você repita uma opção, mas usa 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 uma enumeração 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 do 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 de 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 argumento e como personalizá-la, confira as seguintes seções no artigo Associação de parâmetros:
Confira também
- Visão geral de System.CommandLine
- Associação de parâmetro