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:

Consulte também