代码之家  ›  专栏  ›  技术社区  ›  Paul Stovell

解析C中命令行参数的最佳方法?[关闭]

  •  733
  • Paul Stovell  · 技术社区  · 17 年前

    当构建接受参数的控制台应用程序时,可以使用传递给 Main(string[] args) .

    在过去,我只是索引/循环该数组,并做了一些正则表达式来提取值。但是,当命令变得更复杂时,解析会变得非常难看。

    所以我感兴趣的是:

    • 您使用的库
    • 你使用的模式

    假设命令始终遵循通用标准,例如 answered here .

    20 回复  |  直到 13 年前
        1
  •  324
  •   Antony Perkov    15 年前

    我强烈建议使用 NDesk.Options ( Documentation )和/或 Mono.Options (相同的API,不同的命名空间)。安 example from the documentation :

    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;
    }
    
        2
  •  198
  •   Xavier Poinas    13 年前

    我很喜欢命令行分析器库( 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();
        }
    }
    
        3
  •  50
  •   Matt Hamilton    17 年前

    这个 WPF TestApi library 附带了C开发中最好的命令行解析器之一。我强烈建议从 Ivo Manolov's blog on the 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);
    
        5
  •  14
  •   skolima    16 年前

    看起来每个人都有自己的宠物命令行解析器,图中我最好也添加我的)。

    http://bizark.codeplex.com/

    此库包含 command-line parser 它将使用命令行中的值初始化类。它有很多特性(我已经建立了很多年)。

    documentation

    Bizark框架中的命令行分析具有以下主要功能:

    • 自动初始化: 类属性是根据命令行参数自动设置的。
    • 默认属性: 在不指定属性名的情况下发送值。
    • 值转换: 使用bizark中还包含的强大convertex类将值转换为正确的类型。
    • 布尔标志: 标记可以通过使用参数(例如,/b表示真,/b-表示假)或添加值true/false、yes/no等来指定。
    • 参数数组: 只需在命令行名称后添加多个值,即可设置定义为数组的属性。例如,/x 1 2 3将用数组1、2、3填充x(假设x定义为整数数组)。
    • 命令行别名: 属性可以支持多个命令行别名。例如,帮助使用别名?.
    • 部分名称识别: 您不需要拼写出全名或别名,只需拼写足够让解析器将属性/别名与其他属性/别名消除歧义即可。
    • 支持ClickOnce: 即使将属性指定为ClickOnce部署的应用程序的URL中的查询字符串,也可以初始化属性。命令行初始化方法将检测它是否以clickOnce的形式运行,因此您的代码在使用时不需要更改。
    • 自动创建/?帮助: 这包括考虑到控制台宽度的良好格式。
    • 将命令行参数加载/保存到文件: 如果要多次运行多个大型、复杂的命令行参数集,则此功能尤其有用。
        6
  •  13
  •   PeterH    16 年前

    不久前我编写了一个C命令行参数分析器。其AT: http://www.codeplex.com/CommandLineArguments

        7
  •  9
  •   Colonel Panic    14 年前

    CLAP (命令行参数解析器)有一个可用的API,并且有很好的文档记录。您可以创建一个方法,对参数进行注释。 https://github.com/adrianaisemberg/CLAP

        8
  •  5
  •   csharptest.net    15 年前

    这个问题有很多解决办法。为了完整性和提供备选方案,如果有人愿意,我在我的 google code library .

    第一个是argumentlist,它只负责解析命令行参数。它收集由开关'/x:y'或'-x=y'定义的名称-值对,还收集“未命名”条目的列表。它是基本的 usage is discussed here , view the class here .

    第二部分是 CommandInterpreter 它从.NET类中创建了一个功能齐全的命令行应用程序。举个例子:

    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“字符串值”5

    --或者——

    program.exe dosomething/ivalue=5-sValue:“字符串值”

    它是如此简单,或是你所需要的那么复杂。你可以 review the source code , view the help download the binary .

        9
  •  4
  •   Xn0vv3r    17 年前

    我喜欢 that one ,因为您可以为参数“定义规则”,无论是否需要,…

    或者如果你是一个Unix用户,你可能会喜欢 GNU Getopt .NET 端口。

        10
  •  4
  •   Phill Tew    14 年前

    你可能喜欢我的 Rug.Cmd

    易于使用和扩展的命令行参数分析器。句柄:bool、加号/减号、字符串、字符串列表、csv、枚举。

    内置的'/'?帮助模式。

    内置的?“和”/?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);
            }
        }
    }
    

    编辑:这是我的项目,因此这个答案不应该被视为第三方的认可。也就是说,我确实在编写的每个基于命令行的程序中使用它,它是开源的,我希望其他人也能从中受益。

        11
  •  3
  •   Jerome    17 年前

    在处有一个命令行参数分析器 http://www.codeplex.com/commonlibrarynet

    它可以使用
    1。属性
    2。显式调用
    三。多个参数或字符串数组的单行

    它可以处理以下事情:

    - 配置 QA - 开始日期 ${ 今天 }- 区域 :“纽约”设置01

    它很容易使用。

        12
  •  2
  •   Chris S    17 年前

    这是我根据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, 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;
        }
    }
    
        13
  •  2
  •   Raphael Bossek    15 年前

    我个人最喜欢的是 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;
    }
    
        14
  •  2
  •   Cristian Lupascu    15 年前

    我最近遇到了fubucore命令行解析实现,我非常喜欢它,原因是:

    • 它很容易使用-尽管我找不到它的文档,fubucore解决方案还提供了一个包含一组很好的单元测试的项目,这些测试比任何文档都更能说明功能性。
    • 它有一个很好的面向对象的设计,没有代码重复或其他类似的东西,我以前在命令行解析应用程序中使用过。
    • 它是声明性的:您基本上为命令和参数集编写类,并用属性修饰它们以设置各种选项(例如名称、描述、强制/可选)
    • 库甚至根据这些定义打印出一个很好的使用图。

    下面是一个关于如何使用这个的简单示例。为了说明用法,我编写了一个简单的实用程序,它有两个命令: -添加(向列表中添加对象-对象由名称(字符串)、值(int)和布尔标志组成) -列表(列出当前添加的所有对象)

    首先,我为“add”命令编写了一个命令类:

    [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
      -------------------------------------
    
        15
  •  2
  •   hannasm    14 年前

    PowerShell命令。

    PowerShell基于在commandlets上指定的属性进行的分析,支持验证、参数集、管道、错误报告、帮助,最好是返回.NET对象以在其他commandlets中使用。

    我发现一些有用的入门链接:

        16
  •  2
  •   Bernard    14 年前

    C# CLI 是一个非常简单的命令行参数解析库,我写的。它有良好的文档记录和开源。

        17
  •  1
  •   devdimi    17 年前

    Genghis Command Line Parser 可能有点过时了,但它的功能非常完整,对我来说工作得很好。

        18
  •  0
  •   Stuart Lange    16 年前

    我建议开放源码库 CSharpOptParse . 它解析命令行,并使用命令行输入水合用户定义的.NET对象。在编写C控制台应用程序时,我总是使用这个库。

        19
  •  0
  •   Andreas    15 年前

    请使用apache commons cli api的.net端口。这很管用。

    http://sourceforge.net/projects/dotnetcli/

    以及用于概念和介绍的原始API

    http://commons.apache.org/cli/

        20
  •  0
  •   Martin Lütken    15 年前

    一个非常简单、易于使用的特殊类,用于命令行分析,它支持默认参数。

    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"));
        }
    }
    
    推荐文章