zoukankan      html  css  js  c++  java
  • 使用ACE_Get_Opt解析命令行

    当我们用C++开发一些C++控制台小工具时,会需要一些用户输入的参数来决定程序如何工作和执行,而用户输入参数的方式大部分都是采用命令行参数的方式。

    比如上一篇文章 玩转Windows服务系列——命令行管理Windows服务 中介绍的sc和net工具。

    既然命令行参数这么普遍也这么有用,那么就有必要学习一下如何解析命令行参数。

    如何解析命令行参数

    那么命令行参数要如何解析呢。

    最最最笨的办法就是每次程序中需要解析命令行参数时,就写一堆解析的代码,但是这样的效率其实很低的,不如使用开源库中的帮助类来解析。

    我所了解的开源库的帮助类有

    • ACE库的ACE_Get_Opt
    • boost的Program_options

    ACE_Get_Opt类的主要使用方法介绍

    那么我们主要看一下ACE_Get_Opt类

    先看它的构造方法

    ACE_Get_Opt (int argc,
                ACE_TCHAR **argv,
                const ACE_TCHAR *optstring = ACE_TEXT (""),
                int skip_args = 1,
                int report_errors = 0,
                int ordering = PERMUTE_ARGS,
                int long_only = 0);

    下面是代码中的注释

    /**
    * Constructor initializes the command line to be parsed. All information
    * for parsing must be supplied to this constructor.
    *
    * @param argc          The number of @a argv elements to parse.
    * @param argv          Command line tokens, such as would be passed
    *                      to @c main().
    * @param optstring     Nul-terminated string containing the legitimate
    *                      short option characters.  A single colon ":"
    *                      following an option character means the option
    *                      requires an argument.  A double colon "::" following
    *                      an option character means the argument is optional.
    *                      The argument is taken from the rest of the current
    *                      @a argv element, or from the following @a argv
    *                      element (only valid for required arguments;
    *                      optional arguments must always reside in the same
    *                      @a argv element). The argument value, if any is
    *                      returned by the @c opt_arg() method.
    *                      @a optstring can be extended by adding long options
    *                      with corresponding short options via the
    *                      @c long_option() method.  If the short option
    *                      already appears in @a optstring, the argument
    *                      characteristics must match, otherwise it is added.
    *                      See @c long_option() for more information.
    *                      If 'W', followed by a semi-colon ';' appears in
    *                      @a optstring, then any time a 'W' appears on the
    *                      command line, the following argument is treated as
    *                      a long option.  For example, if the command line
    *                      contains "program -W foo", "foo" is treated as a
    *                      long option, that is, as if "program --foo" had
    *                      been passed.
    *                      The following characters can appear in @a optstring
    *                      before any option characters, with the described
    *                      effect:
    *                      - '+' changes the @a ordering to @a REQUIRE_ORDER.
    *                      - '-' changes the @a ordering to @a RETURN_IN_ORDER.
    *                      - ':' changes the return value from @c operator()
    *                            and get_opt() from '?' to ':' when an option
    *                            requires an argument but none is specified.
    *
    * @param skip_args     Optional (default 1). The specified number of
    *                      initial elements in @a argv are skipped before
    *                      parsing begins. Thus, the default prevents
    *                      @a argv[0] (usually the command name) from being
    *                      parsed. @a argc includes all @a argv elements,
    *                      including any skipped elements.
    * @param report_errors Optional, if non-zero then parsing errors cause
    *                      an error message to be displayed from the
    *                      @c operator() method before it returns. The
    *                      error message is suppressed if this argument is 0.
    *                      This setting also controls whether or not an error
    *                      message is displayed in @c long_option() encounters
    *                      an error.
    * @param ordering      Optional (default is @c PERMUTE_ARGS); determines
    *                      how the @a argv elements are processed. This argument
    *                      is overridden by two factors:
    *                      -# The @c POSIXLY_CORRECT environment variable. If
    *                         this environment variable is set, the ordering
    *                         is changed to @c REQUIRE_ORDER.
    *                      -# Leading characters in @a optstring (see above).
    *                         Any leading ordering characters override both
    *                         the @a ordering argument and any effect of the
    *                         @c POSIXLY_CORRECT environment variable.
    * @param long_only     Optional. If non-zero, then long options can be
    *                      specified using a single '-' on the command line.
    *                      If the token is not a long option, it is processed
    *                      as usual, that is, as a short option or set of
    *                      short options.
    *
    * Multiple short options can be combined as long as only the last
    * one can takes an argument. For example, if @a optstring is defined as
    * @c "abc:" or @c "abc::" then the command line @e "program -abcxxx" short
    * options @e a, @e b, and @e c are found with @e "xxx" as the argument for
    * @e c.
    * However, if the command line is specified as @e "program -acb" only
    * options @e a and @e c are found with @e "b" as the argument for @e c.
    * Also, for options with optional arguments, that is, those followed by
    * "::", the argument must be in the same @a argv element, so "program -abc
    * xxx" will only find "xxx" as the argument for @e c if @a optstring is
    * specified as @c "abc:" not @c "abc::".
    */

    构造函数共有七个参数,

    argc、argv为程序入口函数main方法的参数,也就是程序的命令行。

    optstring 为指定的参数选项,并且是一个字符作为一个选项,主要包含三种形式

        • 单纯的一个字符选项,比如 s,表示此选项后面不能添加选项的参数
      • 一个字符选项后跟一个冒号,比如 s:,表示此选项后面会有一个参数
      • 一个字符后面跟两个冒号,比如 s::,表示此选项后面即可以有参数也可以无参数

    skip_args 表示从argv的第几个元素开始,默认为1,一般情况下argv[0]为程序的path

    report_errors遇到不识别的参数时是否提示错误

    long_only表示是否只包含字符串的选项参数。

    下面解释一下 字符选项和字符串选项,也就是 short option 和 long option.

    • short option 以 字符’-’开始,比如 -s
    • long option 以两个字符’-’开始,日入 --server

    这是在默认的情况下,也就是long_only = 0的情况下。而当long_only不等于0的时候,就可以通过-server来表示long option了。

    那么来看一个定义的例子

    ACE_Get_Opt opt(argc, argv, "s:u:p:", 1, 0);

    三个重载方法long_option的介绍

    由于构造方法中的optstring只能制定short option,所以必须通过long_option方法来指定long option。

    ACE_Get_Opt类中有三个重载的long_option方法,下面来一一介绍

    long_option方法一:

    /// Adds a long option with no corresponding short option.
    /**
     * If the @a name option is seen, @c operator() returns 0.
     *
     * @param name          The long option to add.
     * @param has_arg       Defines the argument requirements for
     *                      the new option.
     *
     * @retval 0  Success
     * @retval -1 The long option can not be added.
     */
    int long_option (const ACE_TCHAR *name,
                     OPTION_ARG_MODE has_arg = NO_ARG);

    这个方法可以增加long_option,第一个参数name表示要添加的option的名字,第二个参数表示这个option是否包含参数,下面是OPTION_ARG_MODE的定义:

    /// Mutually exclusive option argument mode used by long options.
    enum OPTION_ARG_MODE
    {
      /// Doesn't take an argument.
      NO_ARG = 0,
    
      /// Requires an argument, same as passing ":" after a short option
      /// character in @a optstring.
      ARG_REQUIRED = 1,
    
      /// Argument is optional, same as passing "::" after a short
      /// option character in @a optstring.
      ARG_OPTIONAL = 2
    };
    • NO_ARG表示没有参数,对应short option中的没有冒号的情况
    • ARG_REQUIRED表示必须有参数,对应short option中有一个冒号的情况
    • ARG_OPTIONAL表示参数可有可无,对应short option中有两个冒号的情况

    此方法可以这样使用

    if(opt.long_option("server", ACE_Get_Opt::ARG_REQUIRED) == -1)
    {
      cout << "server option can not be added" << endl;
    }

    long_option方法二:

    /// Adds a long option with a corresponding short option.
      /**
       * @param name          The long option to add.
       * @param short_option  A character, the short option that corresponds
       *                      to @a name.
       * @param has_arg       Defines the argument requirements for
       *                      the new option.  If the short option has already
       *                      been supplied in the @a optstring, @a has_arg
       *                      must match or an error is returned; otherwise, the
       *                      new short option is added to the @a optstring.
       *
       * @retval 0  Success
       * @retval -1 The long option can not be added.
       */
      int long_option (const ACE_TCHAR *name,
                       int short_option,
                       OPTION_ARG_MODE has_arg = NO_ARG);

    这个方法中增加了一个short_option参数,表示这个long_option与对应的short_option所表达的意义是一致的,当解析命令行时,遇到这个long_option时,就按此处的short option进行处理。

    此方法可以这样使用

    if(opt.long_option("server", 's', ACE_Get_Opt::ARG_REQUIRED) == -1)
    {
      cout << "server option can not be added" << endl;
    }

    long_option方法三:

    /// Returns the name of the long option found on the last call to
      /// @c operator() or 0 if none was found.
      const ACE_TCHAR *long_option (void) const;

    这个方法表示解析命令行时,如果遇到long_option,则可以通过这个方法来获取是哪一个long_option。

    命令行的解析

    命令行的解析就要依赖 operator()()方法,和opt_arg方法,前者解析遇到的是哪个short option 或者 long option,而 opt_arg方法则获取option的参数。

    下面看一下方法的声明

    /**
     * Scan elements of @a argv (whose length is @a argc) for short option
     * characters given in @a optstring or long options (with no short
     * option equivalents).
     *
     * If an element of @a argv starts with '-', and is not exactly "-"
     * or "--", then it is a short option element.  The characters of this
     * element (aside from the initial '-') are option characters. If
     * it starts with "--" followed by other characters it is treated as
     * a long option.  If @c operator() is called repeatedly, it returns
     * each of the option characters from each of the option elements.
     *
     * @return The parsed option character. The following characters have
     * special significance.
     * @retval 0      A long option was found
     * @retval '?'   Either an unknown option character was found, or the
     *                option is known but requires an argument, none was
     *                specified, and @a optstring did not contain a leading
     *                colon.
     * @retval ':'    A known option character was found but it requires an
     *                argument and none was supplied, and the first character
     *                of @a optstring was a colon. @c opt_opt() indicates
     *                which option was specified.
     * @retval '1'    @c RETURN_IN_ORDER was specified and a non-option argument
     *                was found.
     * @retval EOF No more option characters were found.  @c opt_ind() will
     *             return the index in @a argv of the first @a argv element
     *             that is not an option.  If @c PERMUTE_ARGS was
     *             specified, the @a argv elements have been permuted so that
     *             those that are not options now come last.
     *
     * @note The standards are unclear with respect to the conditions under
     * which '?' and ':' are returned, so we scan the initial characters of
     * @a optstring up unto the first short option character for '+', '-',
     * and ':' in order to determine ordering and missing argument behavior.
     */
    int operator () (void);
    /**
     * For communication from @c operator() to the caller.  When
     * @c operator() finds an option that takes an argument, the argument
     * value is returned from this method, otherwise it returns 0.
     */
    ACE_TCHAR *opt_arg (void) const;

    operator()方法有几种返回值:

    • 具体的option 字符,表示命令行中遇到了此 short option,或者关联了short option的 long option
    • 0,表示遇到了一个long option,可以通过上面介绍的long_option的方法三来获取一下具体是哪一个long option
    • EOF,也就是-1,表示解析结束。

    当operator()方法返回一个short option或者 long option时,如果这个option可以有参数,则通过opt_arg方法来获取具体的参数。

    完整的命令行解析代码

    下面展示一个完整但是比较简单的命令行解析的示例程序代码

    #include "ace/Get_Opt.h"
    #include <iostream>
    using namespace std;
    
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        //定义了三个short option, 类型为 ARG_REQUIRED
        ACE_Get_Opt opt(argc, argv, "s:u:p:", 1, 0);
        //定义三个long option, 并与相应的short option 进行关联
        if(opt.long_option("server", 's', ACE_Get_Opt::ARG_REQUIRED) == -1)
        {
            cout << "server option can not be added" << endl;
        }
        if(opt.long_option("user", 'u', ACE_Get_Opt::ARG_REQUIRED) == -1)
        {
            cout << "user option can not be added" << endl;
        }
        if(opt.long_option("pwd", 'p', ACE_Get_Opt::ARG_REQUIRED) == -1)
        {
            cout << "pwd option can not be added" << endl;
        }
    
        //开始解析
        for(int arg = 0; (arg = opt()) != -1;)
        {
            switch (arg)
            {
            case 's':
                cout << "server is " << opt.opt_arg() << endl;
                break;
            case 'u':
                cout << "user is " << opt.opt_arg() << endl;
                break;
            case 'p':
                cout << "pwd is " << opt.opt_arg() << endl;
                break;
            //解析 long option
            case 0:
                if(_stricmp(opt.long_option(), "server") == 0)
                {
                    cout << "long option server is" << opt.opt_arg() << endl;
                }
                break;
            default:
                break;
            }
        }
        //如果直接运行,或者使用方式不对,则显示帮助
        if(opt.opt_ind() + 2 < argc)
        {
            cout << "the usage is : GetOptTest.exe [option]" << endl;
            cout << "	 [-s] server address" << endl;
            cout << "	 [-u] user name" << endl;
            cout << "	 [-p] password of user" << endl
            << endl;
        }
        return 0;
    }

    命令行解析实战

    至此命令行解析的基本功能已经都介绍了,而且相应的代码已经完成,那么就让我们来欣赏一下解析的效果吧。

    具体的命令行

    -s 127.0.0.1 --server 192.168.0.1 -u hbccdf -p pwdfortest

    运行效果图

    ACE_Get_Opt命令行解析实战

    其实功能很简单,ACE_Get_Opt的使用也很简单,但是一点点学习,并进行总结,是我一直需要提高的地方。以后会坚持把学到的东西进行总结,并分享到博客上。

    坚持!!!

  • 相关阅读:
    【leetcode】Basic Calculator III
    【leetcode】Reorganize String
    【leetcode】Largest Plus Sign
    【leetcode】Reach a Number
    【leetcode】Network Delay Time
    【leetcode】Monotone Increasing Digits
    【leetcode】Submission Details
    【leetcode】Valid Parenthesis String
    【leetcode】Max Area of Island
    New Concept English three(14)
  • 原文地址:https://www.cnblogs.com/hbccdf/p/use_acegetopt_parse_commandline.html
Copyright © 2011-2022 走看看