parser ndesk argument c# .net command-line-arguments

ndesk - ¿La mejor manera de analizar los argumentos de la línea de comandos en C#?



parser command (20)

Commandlets del PowerShell.

El análisis realizado por powershell se basa en los atributos especificados en los commandlets, soporte para validaciones, conjuntos de parámetros, canalización, informes de errores, ayuda y lo mejor de todos los objetos .NET devueltos para su uso en otros commandlets.

Un par de enlaces que me parecieron útiles para comenzar:

Al crear aplicaciones de consola que toman parámetros, puede usar los argumentos pasados ​​a Main(string[] args) .

En el pasado, simplemente he indexado / enlazado esa matriz y he hecho algunas expresiones regulares para extraer los valores. Sin embargo, cuando los comandos se vuelven más complicados, el análisis puede ser bastante feo.

Así que estoy interesado en:

  • Bibliotecas que usas
  • Patrones que utilizas

Suponga que los comandos siempre se adhieren a estándares comunes como los que se responden aquí .



Este es un controlador que escribí basado en la clase de Options Novell.

Éste está dirigido a aplicaciones de consola que ejecutan un ciclo de estilo while while (input !="exit") , una consola interactiva como una consola FTP, por ejemplo.

Ejemplo de uso:

static void Main(string[] args) { // Setup CommandHandler handler = new CommandHandler(); CommandOptions options = new CommandOptions(); // Add some commands. Use the v syntax for passing arguments options.Add("show", handler.Show) .Add("connect", v => handler.Connect(v)) .Add("dir", handler.Dir); // Read lines System.Console.Write(">"); string input = System.Console.ReadLine(); while (input != "quit" && input != "exit") { if (input == "cls" || input == "clear") { System.Console.Clear(); } else { if (!string.IsNullOrEmpty(input)) { if (options.Parse(input)) { System.Console.WriteLine(handler.OutputMessage); } else { System.Console.WriteLine("I didn''t understand that command"); } } } System.Console.Write(">"); input = System.Console.ReadLine(); } }

Y la fuente:

/// <summary> /// A class for parsing commands inside a tool. Based on Novell Options class (http://www.ndesk.org/Options). /// </summary> public class CommandOptions { private Dictionary<string, Action<string[]>> _actions; private Dictionary<string, Action> _actionsNoParams; /// <summary> /// Initializes a new instance of the <see cref="CommandOptions"/> class. /// </summary> public CommandOptions() { _actions = new Dictionary<string, Action<string[]>>(); _actionsNoParams = new Dictionary<string, Action>(); } /// <summary> /// Adds a command option and an action to perform when the command is found. /// </summary> /// <param name="name">The name of the command.</param> /// <param name="action">An action delegate</param> /// <returns>The current CommandOptions instance.</returns> public CommandOptions Add(string name, Action action) { _actionsNoParams.Add(name, action); return this; } /// <summary> /// Adds a command option and an action (with parameter) to perform when the command is found. /// </summary> /// <param name="name">The name of the command.</param> /// <param name="action">An action delegate that has one parameter - string[] args.</param> /// <returns>The current CommandOptions instance.</returns> public CommandOptions Add(string name, Action<string[]> action) { _actions.Add(name, action); return this; } /// <summary> /// Parses the text command and calls any actions associated with the command. /// </summary> /// <param name="command">The text command, e.g "show databases"</param> public bool Parse(string command) { if (command.IndexOf(" ") == -1) { // No params foreach (string key in _actionsNoParams.Keys) { if (command == key) { _actionsNoParams[key].Invoke(); return true; } } } else { // Params foreach (string key in _actions.Keys) { if (command.StartsWith(key) && command.Length > key.Length) { string options = command.Substring(key.Length); options = options.Trim(); string[] parts = options.Split('' ''); _actions[key].Invoke(parts); return true; } } } return false; } }


Existen numerosas soluciones a este problema. Para completar y proporcionar la alternativa si alguien desea, estoy agregando esta respuesta para dos clases útiles en mi biblioteca de códigos de Google .

La primera es ArgumentList, que solo es responsable de analizar los parámetros de la línea de comandos. Recopila pares nombre-valor definidos por los modificadores ''/ x: y'' o ''-x = y'' y también recopila una lista de entradas ''sin nombre''. Su uso básico se discute aquí , vea la clase aquí .

La segunda parte de esto es el CommandInterpreter que crea una aplicación de línea de comandos completamente funcional a partir de su clase .Net. Como ejemplo:

using CSharpTest.Net.Commands; static class Program { static void Main(string[] args) { new CommandInterpreter(new Commands()).Run(args); } //example ‘Commands’ class: class Commands { public int SomeValue { get; set; } public void DoSomething(string svalue, int ivalue) { ... }

Con el código de ejemplo anterior puede ejecutar lo siguiente:

Program.exe DoSomething "valor de cadena" 5

- o -

Program.exe dosomething / ivalue = 5 -svalue: "string value"

Es tan simple como eso o tan complejo como lo necesitas. Puede revisar el código fuente , ver la ayuda o descargar el binario .


Hace poco me encontré con la implementación del análisis de la línea de comandos de FubuCore que realmente me gusta, las razones son:

  • es fácil de usar, aunque no pude encontrar una documentación para ello, la solución FubuCore también proporciona un proyecto que contiene un conjunto agradable de Pruebas unitarias que hablan más sobre la funcionalidad que cualquier otra documentación.
  • tiene un bonito diseño orientado a objetos, sin repetición de código u otras cosas que solía tener en mis aplicaciones de análisis de línea de comandos
  • es declarativo: básicamente escribe clases para los Comandos y conjuntos de parámetros y los decora con atributos para configurar varias opciones (por ejemplo, nombre, descripción, obligatorio / opcional)
  • La biblioteca incluso imprime un buen gráfico de uso, basado en estas definiciones.

A continuación se muestra un ejemplo simple sobre cómo usar esto. Para ilustrar el uso, he escrito una utilidad simple que tiene dos comandos: - agregar (agrega un objeto a una lista - un objeto consiste en un nombre (cadena), valor (int) y una bandera booleana) - lista (listas todos los objetos añadidos actualmente)

En primer lugar, escribí una clase de comando para el comando ''agregar'':

[Usage("add", "Adds an object to the list")] [CommandDescription("Add object", Name = "add")] public class AddCommand : FubuCommand<CommandInput> { public override bool Execute(CommandInput input) { State.Objects.Add(input); // add the new object to an in-memory collection return true; } }

Este comando toma una instancia de CommandInput como parámetro, así que defino eso a continuación:

public class CommandInput { [RequiredUsage("add"), Description("The name of the object to add")] public string ObjectName { get; set; } [ValidUsage("add")] [Description("The value of the object to add")] public int ObjectValue { get; set; } [Description("Multiply the value by -1")] [ValidUsage("add")] [FlagAlias("nv")] public bool NegateValueFlag { get; set; } }

El siguiente comando es "lista", que se implementa de la siguiente manera:

[Usage("list", "List the objects we have so far")] [CommandDescription("List objects", Name = "list")] public class ListCommand : FubuCommand<NullInput> { public override bool Execute(NullInput input) { State.Objects.ForEach(Console.WriteLine); return false; } }

El comando ''list'' no toma parámetros, así que definí una clase NullInput para esto:

public class NullInput { }

Todo lo que queda ahora es conectar esto con el método Main (), así:

static void Main(string[] args) { var factory = new CommandFactory(); factory.RegisterCommands(typeof(Program).Assembly); var executor = new CommandExecutor(factory); executor.Execute(args); }

El programa funciona como se esperaba, imprimiendo sugerencias sobre el uso correcto en caso de que algún comando no sea válido:

------------------------ Available commands: ------------------------ add -> Add object list -> List objects ------------------------

Y una muestra de uso para el comando ''agregar'':

Usages for ''add'' (Add object) add <objectname> [-nv] ------------------------------------------------- Arguments ------------------------------------------------- objectname -> The name of the object to add objectvalue -> The value of the object to add ------------------------------------------------- ------------------------------------- Flags ------------------------------------- [-nv] -> Multiply the value by -1 -------------------------------------


Hay un analizador de argumentos de línea de comando en http://www.codeplex.com/commonlibrarynet

Puede analizar argumentos usando
1. atributos
2. llamadas explícitas
3. Una sola línea de múltiples argumentos O una matriz de cadenas

Puede manejar cosas como las siguientes:

- config : Qa - startdate : $ { today } - region : ''New York'' Settings01

Es muy fácil de usar.


La biblioteca WPF TestApi viene con uno de los analizadores de línea de comandos más agradables para el desarrollo de C #. Recomiendo encarecidamente buscarlo en el blog de Ivo Manolov sobre la API :

// EXAMPLE #2: // Sample for parsing the following command-line: // Test.exe /verbose /runId=10 // This sample declares a class in which the strongly- // typed arguments are populated public class CommandLineArguments { bool? Verbose { get; set; } int? RunId { get; set; } } CommandLineArguments a = new CommandLineArguments(); CommandLineParser.ParseArguments(args, a);


Me gusta ese , porque puedes "definir reglas" para los argumentos, necesarios o no, ...

o si eres un chico de Unix, te puede gustar el puerto .NET de GNU Getopt .


Mi favorito personal es http://www.codeproject.com/KB/recipes/plossum_commandline.aspx por Peter Palotas:

[CommandLineManager(ApplicationName="Hello World", Copyright="Copyright (c) Peter Palotas")] class Options { [CommandLineOption(Description="Displays this help text")] public bool Help = false; [CommandLineOption(Description = "Specifies the input file", MinOccurs=1)] public string Name { get { return mName; } set { if (String.IsNullOrEmpty(value)) throw new InvalidOptionValueException( "The name must not be empty", false); mName = value; } } private string mName; }



Parece que todo el mundo tiene sus propios analizadores de línea de comandos para mascotas, imagino que es mejor que yo agregue el mío también :).

http://bizark.codeplex.com/

Esta biblioteca contiene un analizador de línea de comandos que inicializará una clase con los valores de la línea de comandos. Tiene un montón de características (lo he estado construyendo durante muchos años).

De la documentación ...

El análisis de línea de comandos en el marco de BizArk tiene estas características clave:

  • Inicialización automática: las propiedades de la clase se establecen automáticamente en función de los argumentos de la línea de comandos.
  • Propiedades predeterminadas: envíe un valor sin especificar el nombre de la propiedad.
  • Conversión de valor: utiliza la poderosa clase ConvertEx también incluida en BizArk para convertir los valores al tipo adecuado.
  • Banderas booleanas: las banderas se pueden especificar simplemente usando el argumento (ej, / b para verdadero y / b- para falso) o agregando el valor verdadero / falso, sí / no, etc.
  • Matrices de argumentos: simplemente agregue varios valores después del nombre de la línea de comandos para establecer una propiedad que se define como una matriz. Ex, / x 1 2 3 llenará x con la matriz {1, 2, 3} (suponiendo que x se define como una matriz de enteros).
  • Alias ​​de línea de comando: una propiedad puede admitir múltiples alias de línea de comando para ella. Por ejemplo, ¿Ayuda usa el alias?
  • Reconocimiento parcial de nombres: no necesita deletrear el nombre completo o el alias, solo hágalo lo suficiente para que el analizador pueda desambiguar la propiedad / alias de los demás.
  • Admite ClickOnce: puede inicializar propiedades incluso cuando se especifican como la cadena de consulta en una URL para las aplicaciones implementadas por ClickOnce. El método de inicialización de la línea de comandos detectará si se está ejecutando como ClickOnce o no, por lo que su código no necesita cambiarse al usarlo.
  • Crea automáticamente /? Ayuda: Esto incluye un formato agradable que tiene en cuenta el ancho de la consola.
  • Cargar / guardar argumentos de línea de comando en un archivo: esto es especialmente útil si tiene varios conjuntos de argumentos de línea de comando grandes y complejos que desea ejecutar varias veces.


Realmente me gusta la biblioteca de analizador de línea de comandos ( http://commandline.codeplex.com/ ). Tiene una forma muy simple y elegante de configurar parámetros a través de atributos:

class Options { [Option("i", "input", Required = true, HelpText = "Input file to read.")] public string InputFile { get; set; } [Option(null, "length", HelpText = "The maximum number of bytes to process.")] public int MaximumLenght { get; set; } [Option("v", null, HelpText = "Print details during execution.")] public bool Verbose { get; set; } [HelpOption(HelpText = "Display this help screen.")] public string GetUsage() { var usage = new StringBuilder(); usage.AppendLine("Quickstart Application 1.0"); usage.AppendLine("Read user manual for usage instructions..."); return usage.ToString(); } }


Recomiendo encarecidamente utilizar NDesk.Options ( Documentation ) y / o Mono.Options (la misma API, espacio de nombres diferente). Un ejemplo de la documentación :

bool show_help = false; List<string> names = new List<string> (); int repeat = 1; var p = new OptionSet () { { "n|name=", "the {NAME} of someone to greet.", v => names.Add (v) }, { "r|repeat=", "the number of {TIMES} to repeat the greeting./n" + "this must be an integer.", (int v) => repeat = v }, { "v", "increase debug message verbosity", v => { if (v != null) ++verbosity; } }, { "h|help", "show this message and exit", v => show_help = v != null }, }; List<string> extra; try { extra = p.Parse (args); } catch (OptionException e) { Console.Write ("greet: "); Console.WriteLine (e.Message); Console.WriteLine ("Try `greet --help'' for more information."); return; }


Sugeriría la biblioteca de código abierto CSharpOptParse . Analiza la línea de comandos e hidrata un objeto .NET definido por el usuario con la entrada de la línea de comandos. Siempre recurro a esta biblioteca cuando escribo una aplicación de consola C #.


Te puede gustar mi una Rug.Cmd

Analizador de argumentos de línea de comando fácil de usar y expandible. Manijas: Bool, Más / Menos, Cadena, Lista de cadenas, CSV, Enumeración.

Construido en ''/?'' modo de ayuda.

Construido en ''/ ??'' y los modos de generador de documentos ''/? D''.

static void Main(string[] args) { // create the argument parser ArgumentParser parser = new ArgumentParser("ArgumentExample", "Example of argument parsing"); // create the argument for a string StringArgument StringArg = new StringArgument("String", "Example string argument", "This argument demonstrates string arguments"); // add the argument to the parser parser.Add("/", "String", StringArg); // parse arguemnts parser.Parse(args); // did the parser detect a /? argument if (parser.HelpMode == false) { // was the string argument defined if (StringArg.Defined == true) { // write its value RC.WriteLine("String argument was defined"); RC.WriteLine(StringArg.Value); } } }

Edición: este es mi proyecto y, como tal, esta respuesta no debe verse como un aval de un tercero. Dicho esto, lo uso para cada programa basado en la línea de comandos que escribo, es de código abierto y espero que otros puedan beneficiarse de él.


Una clase ad hoc muy simple y fácil de usar para el análisis de la línea de comandos, que admite argumentos predeterminados.

class CommandLineArgs { public static CommandLineArgs I { get { return m_instance; } } public string argAsString( string argName ) { if (m_args.ContainsKey(argName)) { return m_args[argName]; } else return ""; } public long argAsLong(string argName) { if (m_args.ContainsKey(argName)) { return Convert.ToInt64(m_args[argName]); } else return 0; } public double argAsDouble(string argName) { if (m_args.ContainsKey(argName)) { return Convert.ToDouble(m_args[argName]); } else return 0; } public void parseArgs(string[] args, string defaultArgs ) { m_args = new Dictionary<string, string>(); parseDefaults(defaultArgs ); foreach (string arg in args) { string[] words = arg.Split(''=''); m_args[words[0]] = words[1]; } } private void parseDefaults(string defaultArgs ) { if ( defaultArgs == "" ) return; string[] args = defaultArgs.Split('';''); foreach (string arg in args) { string[] words = arg.Split(''=''); m_args[words[0]] = words[1]; } } private Dictionary<string, string> m_args = null; static readonly CommandLineArgs m_instance = new CommandLineArgs(); } class Program { static void Main(string[] args) { CommandLineArgs.I.parseArgs(args, "myStringArg=defaultVal;someLong=12"); Console.WriteLine("Arg myStringArg : ''{0}'' ", CommandLineArgs.I.argAsString("myStringArg")); Console.WriteLine("Arg someLong : ''{0}'' ", CommandLineArgs.I.argAsLong("someLong")); } }



C # CLI es una biblioteca de análisis de argumentos de línea de comandos muy simple que escribí. Está bien documentado y es de código abierto.