Best way to parse command line arguments in C#?
当构建接受参数的控制台应用程序时,可以使用传递给
在过去,我只是索引/循环该数组,并做了一些正则表达式来提取值。但是,当命令变得更复杂时,解析会变得非常难看。
所以我感兴趣的是:
- 您使用的库
- 你使用的模式
假设命令始终遵循常见标准,如此处所回答的标准。
我强烈建议使用ndesk.options(文档)和/或mono.options(相同的API,不同的命名空间)。文档中的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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. " + "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; } |
我非常喜欢命令行解析器库(http://command line.codeplex.com/)。它有一种通过属性设置参数的非常简单和优雅的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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开发的最好的命令行解析器之一。我强烈建议从Ivo Manolov在API上的博客中查看:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 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); |
查看http://github.com/mono/mono/tree/master/mcs/class/mono.options/
看起来每个人都有自己的宠物命令行解析器,图中我最好也添加我的)。
http://bizark.codeplex.com/
这个库包含一个命令行分析器,它将用命令行中的值初始化一个类。它有很多功能(我已经建立了很多年)。
从文档中…
Bizark框架中的命令行分析具有以下主要功能:
- 自动初始化:类属性是根据命令行参数自动设置的。
- 默认属性:在不指定属性名的情况下发送值。
- 值转换:使用bizark中还包含的强大convertex类将值转换为正确的类型。
- 布尔标记:标记可以通过简单地使用参数(例如,/b表示真,/b-表示假)或添加值true/false、yes/no等来指定。
- 参数数组:只需在命令行名称后添加多个值,即可设置定义为数组的属性。例如,/x 1 2 3将用数组1、2、3填充x(假设x定义为整数数组)。
- 命令行别名:属性可以支持多个命令行别名。例如,帮助使用别名?.
- 部分名称识别:您不需要拼写出完整的名称或别名,只要拼写足够让解析器从其他属性/别名中消除歧义即可。
- 支持ClickOnce:可以初始化属性,即使它们被指定为ClickOnce部署的应用程序的URL中的查询字符串。命令行初始化方法将检测它是否以clickOnce的形式运行,因此在使用时不需要更改代码。
- 自动创建/?帮助:这包括考虑到控制台宽度的好格式。
- 将命令行参数加载/保存到文件中:如果您有多个要多次运行的大型、复杂的命令行参数集,这尤其有用。
不久前我编写了一个C命令行参数分析器。网址:http://www.codeplex.com/commandlinearguments
CLAP(命令行参数解析器)有一个可用的API,并且有很好的文档记录。您可以创建一个方法,对参数进行注释。网址:https://github.com/adrianaisemberg/clap
这个问题有很多解决办法。为了完整性和提供备选方案,如果有人愿意,我在我的谷歌代码库中为两个有用的类添加了这个答案。
第一个是argumentlist,它只负责解析命令行参数。它收集由开关'/x:y'或'-x=y'定义的名称-值对,还收集"未命名"条目的列表。这里讨论了它的基本用法,在这里查看类。
第二部分是命令解释器,它从.NET类中创建一个功能完整的命令行应用程序。举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
通过上面的示例代码,您可以运行以下代码:
Program.exe DoSomething"string value" 5
--或者——
Program.exe dosomething /ivalue=5 -svalue:"string value"
它是如此简单,或是你所需要的那么复杂。您可以查看源代码、查看帮助或下载二进制文件。
你可以喜欢我的一块地毯。
易于使用和扩展的命令行参数分析器。句柄:bool、加号/减号、字符串、字符串列表、csv、枚举。
内置的'/'?帮助模式。
内置的?"和"/?d'文档生成器模式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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); } } } |
编辑:这是我的项目,因此这个答案不应该被视为第三方的认可。也就是说,我确实在编写的每个基于命令行的程序中使用它,它是开源的,我希望其他人也能从中受益。
我喜欢这个,因为你可以为参数"定义规则",无论需要与否,…
或者如果你是一个Unix用户,你可能会喜欢gnu getopt.net端口。
在http://www.codeplex.com/commonlibrarynet上有一个命令行参数分析器
它可以使用1。属性2。显式调用三。多个参数或字符串数组的单行
它可以处理以下事情:
-配置:qa-开始日期:$今天-地区:'纽约'设置01
它很容易使用。
我个人最喜欢的是http://www.codeproject.com/kb/recipes/plossum_commandline.aspx,作者:Peter Palotas:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [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; } |
C cli是我编写的一个非常简单的命令行参数解析库。它有良好的文档记录和开源。
我最近遇到了fubucore命令行解析实现,我非常喜欢它,原因是:
- 它很容易使用-尽管我找不到它的文档,fubucore解决方案还提供了一个包含一组很好的单元测试的项目,这些测试比任何文档都更能说明功能性。
- 它有一个很好的面向对象的设计,没有代码重复或其他类似的东西,我以前在命令行解析应用程序中使用过。
- 它是声明性的:您基本上为命令和参数集编写类,并用属性修饰它们以设置各种选项(例如名称、描述、强制/可选)
- 库甚至根据这些定义打印出一个很好的使用图。
下面是一个关于如何使用这个的简单示例。为了说明用法,我编写了一个简单的实用程序,它有两个命令:-添加(向列表中添加对象-对象由名称(字符串)、值(int)和布尔标志组成)-列表(列出当前添加的所有对象)
首先,我为"add"命令编写了一个命令类:
1 2 3 4 5 6 7 8 9 10 11 | [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实例作为参数,因此我定义下一个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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",其实现如下:
1 2 3 4 5 6 7 8 9 10 11 | [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类:
1 | public class NullInput { } |
现在只剩下在main()方法中连接它,如下所示:
1 2 3 4 5 6 7 8 9 |
程序按预期工作,在任何命令无效时打印有关正确使用的提示:
1 2 3 4 5 6 | ------------------------ Available commands: ------------------------ add -> Add object list -> List objects ------------------------ |
以及"add"命令的示例用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 ------------------------------------- |
这是我基于Novell
这一个是针对执行
示例用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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(); } } |
来源:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | /// <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; } } |
PowerShell命令。
PowerShell基于在commandlets上指定的属性进行的分析,支持验证、参数集、管道、错误报告、帮助,最好是返回.NET对象以在其他commandlets中使用。
我发现一些有用的入门链接:
- 快速入门教程
- msdn编程指南
- msdn上的命名空间引用
成吉思的命令行解析器可能有点过时,但它的功能非常完整,对我来说工作得很好。
请使用apache commons cli api的.net端口。这很管用。
http://sourceforge.net/projects/dotnetcli/
以及用于概念和介绍的原始API
http://commons.apache.org/cli/
一个非常简单、易于使用的特殊类,用于命令行分析,它支持默认参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | 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")); } } |
我建议使用开源库csharpotparse。它解析命令行,并使用命令行输入水合用户定义的.NET对象。在编写C控制台应用程序时,我总是使用这个库。