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: