当我们用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 << "\t [-s] server address" << endl;
cout << "\t [-u] user name" << endl;
cout << "\t [-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解析命令行的更多相关文章

  1. ACE_Get_Opt解析命令行

    ACE_Get_Opt是一种解析命令行参数选项的迭代器. 1:构造方法 ACE_Get_Opt需要引用头文件,#include "ace/Get_Opt.h". ACE_Get_O ...

  2. boost之program_options库,解析命令行参数、读取配置文件

    一.命令行解析 tprogram_options解析命令行参数示例代码: #include <iostream> using namespace std; #include <boo ...

  3. shell解析命令行的过程以及eval命令

    本文说明的是一条linux命令在执行时大致要经过哪些过程?以及这些过程的大致顺序. 1.1 shell解析命令行 shell读取和执行命令时的大致操作过程如下图: 以执行以下命令为例: echo -e ...

  4. optparse模块解析命令行参数的说明及优化

    一.关于解析命令行参数的方法 关于“解析命令行参数”的方法我们一般都会用到sys.argv跟optparse模块.关于sys.argv,网上有一篇非常优秀的博客已经介绍的很详细了,大家可以去这里参考: ...

  5. python解析命令行参数

    常常需要解析命令行参数,经常忘记,好烦,总结下来吧. 1.Python 中也可以所用 sys 的 sys.argv 来获取命令行参数: sys.argv 是命令行参数列表 参数个数:len(sys.a ...

  6. C#/.NET 使用 CommandLineParser 来标准化地解析命令行

    CommandLineParser 是一款用于解析命令行参数的 NuGet 包.你只需要关注你的业务,而命令行解析只需要极少量的配置代码. 本文将介绍如何使用 CommandLineParser 高效 ...

  7. 使用 Apache Commons CLI 解析命令行参数示例

    很好的输入参数解析方法 ,转载记录下 转载在: https://www.cnblogs.com/onmyway20xx/p/7346709.html Apache Commons CLI 简介 Apa ...

  8. linux 中解析命令行参数(getopt_long用法)

    linux 中解析命令行参数(getopt_long用法) http://www.educity.cn/linux/518242.html 详细解析命令行的getopt_long()函数 http:/ ...

  9. (转)shell解析命令行的过程以及eval命令

    shell解析命令行的过程以及eval命令   本文说明的是一条linux命令在执行时大致要经过哪些过程?以及这些过程的大致顺序. 1.1 shell解析命令行 shell读取和执行命令时的大致操作过 ...

随机推荐

  1. B-Tree 学习

    算法导论 第18章 B树与其他树的结构不同的是  B数是多叉而不是二叉树 而且分叉因子很大一般使用于数据库 针对需要硬盘IO的情况而使用 可以降低磁盘IOB树的一个节点是以磁盘的页面为单位,而不是数据 ...

  2. vim的撤销和恢复操作以及匹配当前单词操作

    今天顺便看了一下vim的一点命令,记录一下 1.撤销上一次操作和恢复上一次操作: u → undo <C-r> → redo 2.搜索上一个单词和下一个单词 * 和 #: 匹配光标当前所在 ...

  3. vim 查看文件二进制格式

    用vim打开文件,vim -b file,选项-b是二进制模式打开   然后输入 :%!xxd,就可看到二进制编码     其实在linux下,直接输入xxd file 也是可以看到的文件二进制格式的

  4. REST有状态与无状态的理解

    1. 什么是REST? REST(REpresentation State Transfer)表述性状态传递,是一种软件架构风格,是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可 ...

  5. Jmeter在linux上运行(命令行运行Jmeter)

    1.下载安装 http://jmeter.apache.org/download_jmeter.cgi Jmeter官网下载 linux下应使用tgz包,下载  Binaries apache-jme ...

  6. ASP.NET MVC分页组件MvcPager 2.0版发布暨网站全新改版

    MvcPager分页控件是在ASP.NET MVC Web应用程序中实现分页功能的一系列扩展方法,该分页控件的最初的实现方法借鉴了网上流行的部分源代码, 尤其是ScottGu的PagedList< ...

  7. Enterprise app deployment on iOS 7.1 by github

    在iOS7.1以上版本通过Url分发企业应用时,需要采用SSL方式分发plist.如果采用http方式,就会报“无法安装应用程序,因为"example.com"的证书无效.”正确的 ...

  8. Affinity Propagation Algorithm

    The principle of Affinity Propagation Algorithm is discribed at above. It is widly applied in many f ...

  9. Notes for Studying Django

    Once you added a new application to INSTALLED_APPS, the database tables need to be updated, thus you ...

  10. 用CSS绘制箭头等三角形图案 [译]

    最近重新设计了我的网站,准备添加tooltips提示信息效果.实现很容易,但我想要让提示功能具有三角形的指示图标.当我重新思考想要所设计的每个图标颜色都随心所欲的时候,采用图片那就是一场灾难.幸运的是 ...