如何开发命令行程序

    技术2022-05-11  21

    http://blog.csdn.net/luckheadline

    一. 命令行规范

    关于实现命令行参数, C 语言有着由来已久的传统规范。

    1. 可选命令行参数前有一个“ - ”, DOS WINDOWS 系统也可以用“ / ”。

    2. 多个可选命令行参数之间没有顺序要求,每个参数都可以放置在参数列表中的任何位置。

    3. 可选命令行参数本身可能会带有参数。

    4. 可能有些命令行程序并不遵从以上的规范,虽然这样做并不推荐。

     

     

    二. 如何实现命令行参数处理(以 C 语言为例)

        命令行参数总是表现为一个字符串数组,这个字符串数组被称为 ”argv”( 代表 arguments values), 还有一个整数 argc( 代表 arguments count) 用来表示命令行参数列表中参数的个数。因此,我们的 main 函数的格式如下:

            int main(int argc, char* argv[]), 务必要记住 argv[0] 是程序的名字,在 usage 声明中你可能会用到它。 main 函数中的第一任务是实现可选参数,操作 argv 的标准方式如下所示:

     

     

    int  i; int  quiet=0;  //Value for the “-q” optional argument. for  (i = 1; i < argc; i ++)  //skip argv[0]. { /*  *Use the ‘strcmp’ function to compare the argv values to a string  *of your choice(here, it’s a *optinal argument “-q”). When  *strcmp returns 0, it means that the two strings are identical. */      if  (strcmp(argv[i], “-q”) == 0)  //Process optional arguments     {         quiet = 1;  //This is used as a Boolean value.     }      else     {          //Process non-optional arguments here.     } }

    请注意,正如这段代码所示,可选参数“

    -q ”可以被放置于参数列表的任何位置而且程序都可以正常 work 如果可选参数本身还有参数的话,那么代码将更加的 trickier

     

     

     

    int  i; int  opt = 0; int  optarg1 = 0; int  optarg2 = 0; for  (i = 1; i < argc; i ++) {      if  (strcmp(argv[i], “-opt”) == 0)     {         opt = 1;  //This is used as a boolean value.          /*          *The last argument is argv[argc -1]. Make sure there          *are enough arguments.         */          if  (i + 2 <= argc - 1)  //There are enough arguments in argv.         {              /*              *Increment ‘i’ twice so that you don’t check              *these arguments the next time through the loop.             */             i ++;             optarg1 = atoi(argv[i]);  //Convert string to int             i ++;             optarg2 = atoi(argv[i]);         }          else         {              //Print usage statement and exit.         }     }      else     {          //Process non-optional arguments here.     } }

        在很多情况下,命令行处理可能会非常麻烦,不过上面的代码已经可以应付相当多的情况了。

     

     

    BTW, Linux 下,习惯上会有两种形式的命令行参数,一种是短形式,通常由 ”-” 加一个字母组成,这种形式的好处是便捷;另一种是长形式,通常由 ”--” 加一个单词组成,这种形式的好处是形象,好记,直观。

     

     

     

    三. Usage 声明

    有时候,用户可能会输入不合法的命令行参数,你的程序需要处理这种情况以避免程序 crash 。这种情况的正确处理方式是:

    1.   显示 usage 声明

    2.   退出程序

    例如,假设你的程序除了程序名还期望有 3 个参数,并且要接受另外一个可选参数:

    usage 声明的以下几点意见:

     

     

     

    1. usage 信息 : 总是使用“ usage ”开头,接着是程序名和参数名。参数名应该尽可能的指明参数的意义,比如上面的 filename 。参数名不应该包含空格!可选参数使用 [] ,比如上面程序中的 ”-w” 。非可选参数不要使用 [] !总是打印 stderr ,而非 stdout ,以指明程序没有正确 invoke

    2. 程序名:总是使用 argv[0] 以指明程序名而非显式的指出。因为这样,当你重新命名程序之后,不用重写代码。

    3. 退出程序:使用 exit 函数( exit 函数被定义在头文件 <stdlib.h> )。 exit 函数的任何非零参数都标志着程序的非正常结束( exit 0 )标识程序的正常执行,但你很少会像这样用)。你也可以使用宏 EXIT_FAILURE EXIT_SUCCESS 以取代 1 0 作为 exit 函数的参数。

    如果不得不多次写 usage 声明,你可以将它分离出来作为一个独立的函数,并且将程序名( argv[0] )作为参数传给它。那样它就可以被 main 函数在任何需要的时候调用了。

     

    四. 常见错误

    1. 当程序接收到不正确参数时,应该总是打印一个 usage 消息给 stderr 。如果处理失败将会自动 redo

    2. 不要假设可选参数会固定放在参数列表的某个位置上。

    3. 如果不方便的话,就不要尝试一遍处理所有的命令行参数。

    4. 不要修改 argv 数组。

     

    五. getOpt() 的使用

    getOpt() 是一个专门设计来减轻命令行处理负担的库函数。它位于 unistd.h 系统头文件中,其原型如下:

    int getopt(int argc, char *const argv[], const char *optstring);

    函数给定了命令参数的数量 (argc) ,指向这些参数的数组 (argv) 和选项字符串 (optstring) 后, getopt() 将返回第一个选项,并设置一些全局变量。使用相同的参数再次调用该函数时,它将返回下一个选项,并设置相应的全局变量。如果不再有识别到的选项,将返回 -1 ,此任务就完成了。

    getopt() 所设置的全局变量包括:

    optarg :指向当前选项参数(如果有)的指针。

    optind :再次调用 getopt() 时的下一个 argv 指针的索引。

    optopt :最后一个已知选项。

    可以重复调用 getopt() ,直到其返回 -1 为止;任何剩下的命令行参数通常视为文件名或称程序相应的其他内容。见以下代码示例:

     

     

     

    Unix 程序还支持长选项,可以通过使用 getopt_long() 向程序添加长选项支持,因为 getopt_long() 是同时支持长选项和短选项的 getopt() 版本。 getopt_long() 函数还接受其他参数,其中一个是指向 struct option 对象数组的指针。结构如下:

    成员是指向长选项名称(带两个短横线)的指针。 has_arg 成员设置为 no_argument, optional_argument, required_argument (均在 getopt.h 中定义)之一,以指示选项是否具有参数。如果 flag 成员未设置为 NULL ,在处理期间遇到此选项时,会使用 val 成员的值填充它所指向的 int 值。如果 flag 成员为 NULL ,在 getopt_long() 遇到此选项时,将返回 val 中的值;通过将 val 设置为选项的 short 参数,可以在不添加任何其他代码的情况下使用 getopt_long()—— 处理 while loop switch 的现有 getopt() 将自动处理此选项。代码示例可以参见 reference 5

     

     

     

     

     

    Reference:

    http://www.cs.caltech.edu/courses/cs11/material/c/mike/misc/cmdline_args.html

    http://www.ibm.com/developerworks/cn/linux/shell/clutil/index.html

    http://linux.chinaitlab.com/command/4198.html

    http://www.gnu.org/software/libtool/manual/libc/Getopt.html

    http://www.ibm.com/developerworks/cn/aix/library/au-unix-getopt.html

     


    最新回复(0)