Compartir a través de


Cómo definir comandos, opciones y argumentos en System.CommandLine

Importante

System.CommandLine se encuentra actualmente en versión preliminar y esta documentación es para la versión 2.0 beta 4. Parte de la información hace referencia a la versión preliminar del producto, que puede haberse modificado sustancialmente antes de lanzar la versión definitiva. Microsoft no otorga ninguna garantía, explícita o implícita, con respecto a la información proporcionada aquí.

En este artículo se explica cómo definir comandos, opciones y argumentos en aplicaciones de línea de comandos que se compilan con la biblioteca System.CommandLine. Para compilar una aplicación completa que ilustre estas técnicas, consulte el tutorial Introducción a System.CommandLine.

Para obtener instrucciones sobre cómo diseñar los comandos, las opciones y los argumentos de una aplicación de línea de comandos, consulte Guía de diseño.

Definición de un comando raíz

Cada aplicación de línea de comandos tiene un comando raíz, que hace referencia al propio archivo ejecutable. El caso más sencillo para invocar el código, si tiene una aplicación sin subcomandos, opciones o argumentos, tendría este aspecto:

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);
    }
}

Definición de subcomandos

Los comandos pueden tener comandos secundarios, conocidos como subcomandos o verbos, y pueden anidar tantos niveles como necesite. Puede agregar subcomandos tal y como se muestra en el siguiente ejemplo:

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);

El subcomando más interno de este ejemplo se puede invocar de la siguiente manera:

myapp sub1 sub1a

Definición de opciones

Un método de controlador de comandos normalmente tiene parámetros y los valores pueden proceder de las opciones de la línea de comandos. En el ejemplo siguiente se crean dos opciones y se agregan al comando raíz. Los nombres de opción incluyen prefijos de doble guion, lo que es típico de las CLI de POSIX. El código del controlador de comandos muestra los valores de esas opciones:

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);

Este es un ejemplo de entrada de línea de comandos y la salida resultante para el código del ejemplo anterior:

myapp --delay 21 --message "Hello world!"
--delay = 21
--message = Hello world!

Opciones globales

Para agregar una opción a un comando en una sola vez, use el método Add o el AddOption, como se muestra en el ejemplo anterior. Para agregar una opción a un comando y, de forma recursiva, a todos sus subcomandos, use el método AddGlobalOption, como se muestra en el ejemplo siguiente:

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);

El código anterior agrega --delay como una opción global al comando raíz y está disponible en el controlador para subCommand1a.

Definición de argumentos

Los argumentos se definen y se agregan a los comandos como opciones. El ejemplo siguiente es como el ejemplo de las opciones, pero define argumentos en vez de opciones:

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);

Este es un ejemplo de entrada de línea de comandos y la salida resultante para el código del ejemplo anterior:

myapp 42 "Hello world!"
<delay> argument = 42
<message> argument = Hello world!

Un argumento que se define sin un valor predeterminado, como messageArgument en el ejemplo anterior, se trata como un argumento obligatorio. Se muestra un mensaje de error y no se llama al controlador de comandos, si no se proporciona un argumento obligatorio.

Definición de alias

Tanto los comandos como las opciones admiten alias. Puede agregar un alias a una opción llamando a AddAlias:

var option = new Option("--framework");
option.AddAlias("-f");

Con este alias, las siguientes líneas de comandos son equivalentes:

myapp -f net6.0
myapp --framework net6.0

Los alias de comando funcionan de la misma manera.

var command = new Command("serialize");
command.AddAlias("serialise");

Este código hace que las siguientes líneas de comandos sean equivalentes:

myapp serialize
myapp serialise

Se recomienda minimizar el número de alias de opción que defina y evitar definir algunos alias en particular. Para más información, consulte Alias de formato corto.

Opciones necesarias

Para que una opción sea necesaria, establezca su propiedad IsRequired en true, como se muestra en el ejemplo siguiente:

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);

La sección de opciones de la ayuda del comando indica que la opción es necesaria:

Options:
  --endpoint <uri> (REQUIRED)
  --version               Show version information
  -?, -h, --help          Show help and usage information

Si la línea de comandos de esta aplicación de ejemplo no incluye --endpoint, se muestra un mensaje de error y no se llama al controlador de comandos:

Option '--endpoint' is required.

Si una opción necesaria tiene un valor predeterminado, la opción no tiene que especificarse en la línea de comandos. En ese caso, el valor predeterminado proporciona el valor de la opción necesaria.

Comandos, opciones y argumentos ocultos

Es posible que quiera admitir un comando, una opción o un argumento, pero evitar que sea fácil de descubrir. Por ejemplo, podría ser una característica en desuso, administrativa o en vista previa. Use la propiedad IsHidden para evitar que los usuarios descubran estas características con la finalización de tabulación o con la ayuda, como se muestra en el ejemplo siguiente:

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);

La sección de opciones de la ayuda del comando de este ejemplo omite la opción --endpoint.

Options:
  --version               Show version information
  -?, -h, --help          Show help and usage information

Establecer aridad de los argumentos

Puede establecer explícitamente la aridad de los argumentos mediante la propiedad Arity, pero en la mayoría de los casos esto no es necesario. System.CommandLine determina automáticamente la aridad del argumento en función del tipo de argumento:

Tipo de argumento Aridad predeterminada
Boolean ArgumentArity.ZeroOrOne
Tipos de colección ArgumentArity.ZeroOrMore
Todo lo demás ArgumentArity.ExactlyOne

Varios argumentos

De manera predeterminada, al llamar a un comando, puede repetir un nombre de opción para especificar varios argumentos en una opción que tenga una aridad máxima mayor que uno.

myapp --items one --items two --items three

Para permitir varios argumentos sin repetir el nombre de la opción, establezca Option.AllowMultipleArgumentsPerToken en true. Esta configuración le permite escribir la siguiente línea de comandos.

myapp --items one two three

La misma configuración tiene un efecto diferente si la aridad máxima del argumento es 1. Esto le permite repetir una opción, pero solo toma el último valor de la línea. En el ejemplo siguiente, el valor three se pasa a la aplicación.

myapp --item one --item two --item three

Enumerar valores de argumento válidos

Para especificar una lista de valores válidos para una opción o argumento, especifique una enumeración como el tipo de opción o use FromAmong, como se muestra en el ejemplo siguiente:

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");

Este es un ejemplo de entrada de línea de comandos y la salida resultante para el código del ejemplo anterior:

myapp --language not-a-language
Argument 'not-a-language' not recognized. Must be one of:
        'csharp'
        'fsharp'
        'vb'
        'pwsh'
        'sql'

La sección de opciones de la ayuda de comandos muestra los 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

Validación de opciones y argumentos

Para obtener información sobre la validación de argumentos y cómo personalizarlos, consulte las secciones siguientes en el artículo Enlace de parámetros:

Vea también