在C#中parsing命令行参数的最佳方法?
构build带有参数的控制台应用程序时,可以使用传递给Main(string[] args)
。
在过去,我只是索引/循环该数组,并完成了一些正则expression式来提取值。 但是,当命令变得更复杂的时候,parsing会变得非常难看。
所以我很感兴趣:
- 您使用的库
- 你使用的模式
假设这些命令总是遵循这些常见的标准,如在这里回答 。
我强烈build议使用NDesk.Options ( 文档 )和/或Mono.Options (相同的API,不同的命名空间)。 文档中的一个例子 :
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; }
我非常喜欢Command Line Parser Library( http://commandline.codeplex.com/ )。 它有一个非常简单和优雅的通过属性设置参数的方式:
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(); } }
WPF TestApi库为C#开发提供了最好的命令行parsing器之一。 我强烈build议从Ivo Manolov关于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);
看起来每个人都有自己的宠物命令行parsing器,图中我最好添加我的以及:)。
该库包含一个命令行parsing器 ,它将使用命令行中的值初始化一个类。 它有很多function(我已经build立了多年)。
从文档 …
BizArk框架中的命令行parsing具有以下关键特性:
- 自动初始化:类属性是根据命令行参数自动设置的。
- 默认属性:发送一个值,但不指定属性名称。
- 价值转换:使用也包含在BizArk中的强大的ConvertEx类将值转换为正确的types。
- 布尔标志:标志可以通过简单地使用参数(例如,/ b为true和/ b-为false)或通过添加值true / false,yes / no等来指定
- 参数数组:只需在命令行名称后面添加多个值即可设置定义为数组的属性。 例如,/ x 1 2 3将使用数组{1,2,3}来填充x(假设x被定义为一个整数数组)。
- 命令行别名:一个属性可以支持多个命令行别名。 例如,“帮助”使用别名?
- 部分名称识别:您不需要拼出完整的名称或别名,只需拼写足以使parsing器消除其他属性/别名的歧义。
- 支持ClickOnce:即使在ClickOnce部署的应用程序的URL中指定为查询string时,也可以初始化属性。 命令行初始化方法将检测它是否以ClickOnce方式运行,因此在使用代码时不需要更改。
- 自动创build/? 帮助:这包括考虑到控制台的宽度的很好的格式。
- 将命令行参数加载/保存到文件中:如果您有多个要运行多次的大型,复杂的命令行参数集,则这非常有用。
我回写了一个C#命令行参数parsing器。 它在: http : //www.codeplex.com/CommandLineArguments
CLAP (命令行参数parsing器)有一个可用的API,并且有很好的logging。 你做一个方法,注释参数。 https://github.com/adrianaisemberg/CLAP
这个问题有很多解决scheme。 为了完整性,并提供替代如果有人的愿望我添加这个答案在我的谷歌代码库中的两个有用的类。
第一个是ArgumentList,它只负责parsing命令行参数。 它收集由开关'/ x:y'或'-x = y'定义的名称/值对,并收集“未命名”条目的列表。 这里讨论基本用法,在这里 查看这个类 。
第二部分是CommandInterpreter ,它从.Net类中创build一个全function的命令行应用程序。 举个例子:
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) { ... }
通过上面的示例代码,您可以运行以下代码:
Program.exe DoSomething“string值”5
– 要么 –
Program.exe dosomething / ivalue = 5 -svalue:“string值”
它就像你需要的一样简单或复杂。 您可以查看源代码 , 查看帮助或下载二进制文件 。
我喜欢那个 ,因为你可以为争论“定义规则”,不论是否需要,…
或者如果你是一个Unix的人,比你可能喜欢的GNU Getopt .NET端口。
你可能会喜欢我的一个Rug.Cmd
易于使用和可扩展的命令行参数分析器。 句柄:布尔,加号/减号,string,string列表,CSV,枚举。
内置“/?” 帮助模式。
build在“/ ??” 和'/?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); } } }
编辑:这是我的项目,因此这个答案不应被视为来自第三方的认可。 也就是说,我用它来写每一个基于命令行的程序,它是开源的,我希望别人可以从中受益。
在http://www.codeplex.com/commonlibrarynet上有一个命令行参数parsing器;
它可以使用parsing参数
1.属性
2.显式调用
3.多个参数的单行或string数组
它可以处理如下的事情:
– config :Qa – startdate :$ { today } – region :'New York'Settings01
这非常容易使用。
这是一个基于Novell Options
类编写的处理程序。
这一个是针对执行一段while (input !="exit")
样式循环的控制台应用程序,例如交互式控制台,例如FTP控制台。
用法示例:
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(); } }
而来源:
/// <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, eg "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; } }
我个人最喜欢的是Peter Palotas的http://www.codeproject.com/KB/recipes/plossum_commandline.aspx :
[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; }
我最近遇到了FubuCore命令行parsing实现我真的很喜欢它,原因是:
- 它很容易使用 – 虽然我找不到文档,但是FubuCore解决scheme还提供了一个包含一套很好的unit testing的项目,它比任何文档都能说更多的function
- 它有一个很好的面向对象的devise,没有代码重复或其他我曾经在我的命令行parsing应用程序的东西
- 这是声明性的:你基本上为Commands和参数集编写类,并用属性装饰它们来设置各种选项(例如名称,描述,强制性/可选)
- 图书馆甚至根据这些定义打印一个很好的使用图
下面是如何使用这个简单的例子。 为了说明用法,我写了一个简单的实用程序,它有两个命令: – 添加(将对象添加到列表中 – 对象由名称(string),值(int)和布尔标志组成) – 列表所有当前添加的对象)
首先,我为“add”命令写了一个Command类:
[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; } }
这个命令将一个CommandInput实例作为参数,所以我定义了下一个:
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; } }
下一个命令是“list”,它的实现如下:
[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; } }
'list'命令不带任何参数,所以我为此定义了一个NullInput类:
public class NullInput { }
现在剩下的就是把它连接到Main()方法中,如下所示:
static void Main(string[] args) { var factory = new CommandFactory(); factory.RegisterCommands(typeof(Program).Assembly); var executor = new CommandExecutor(factory); executor.Execute(args); }
该程序按预期工作,在任何命令无效的情况下打印有关正确用法的提示:
------------------------ Available commands: ------------------------ add -> Add object list -> List objects ------------------------
以及“add”命令的示例用法:
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 -------------------------------------
Powershell Commandlets。
由基于commandlet上指定属性的powershell进行parsing,支持validation,参数集,stream水线,错误报告,帮助,并最好的返回.NET对象以用于其他命令。
几个链接,我发现有用的入门:
- 快速入门教程
- 编程指南在MSDN上
- 命名空间参考MSDN上
C#CLI是我写的一个非常简单的命令行参数parsing库。 它有很好的文档和开源。
成吉思汗命令行parsing器可能有点过时了,但function非常完整,对我来说工作得非常好。
我会build议开源库CSharpOptParse 。 它parsing命令行并通过命令行input来保存用户定义的.NET对象。 编写C#控制台应用程序时,我总是转向这个库。
一个非常简单易用的命令行parsing专用类,支持默认参数。
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")); } }