Linux 命令行参数分析

来源:互联网 发布:博得之门增强版 mac 编辑:程序博客网 时间:2024/06/05 14:21

 在实际程序之中我们经常要对命令行参数进行分析. 比如我们有一个程序a可以接受许多参数.一个可能的情况是 
a -d print --option1 hello --option2 world 
那么我们如何对这个命令的参数进行分析了?.经常用函数是getopt和getopt_long. 


#include <unistd.h>
#include <getopt.h>

int getopt(int argc,char const **argv, const char *optstring);
int getopt_long(int argc,char const **argc, const char *optstring,const struct option *longopts, int *longindex);

extern char *optarg; 
extern int optind,opterr,optopt;

struct option {
     char *name;
     int has_flag;
     int *flag;
     int value; 
};

getopt_long是getopt的扩展.

getopt接受的命令行参数只可以是以(-)开头, 而getopt_long还可以接受(--)开头的参数. 一般以(-)开头的参数的标志只有一个字母,而以(--)开头的参数可以是一个字符串.如上面的 -d,--option1选项. 
argc和argv参数是main函数的参数.  optstring指出了我们可以接受的参数.其一般的形式为: 参数1[:]参数2[:].... 其中参数是我们可以接受的参数, 如果后面的冒号没有省略, 那么表示这个参数出现时后面必需要带参数值. 比如一个optstring为abc:d:表示这个参数选项可以为a,b,c,d其中c,d出现时候必须要有参数值. 如果我们输入了一个我们没有提供的参数选项.系统将会说 不认识的 选项. getopt返回我们指定的参数选项. 同时将参数值保存在optarg中,如果已经分析完成所有的参数函数返回-1. 这个时候optind指出非可选参数的开始位置. 

#include <stdio.h>
#include <unistd.h>

int main(int argc,char **argv)
{
 int is_a,is_b,is_c,is_d,i;
 char *a_value,*b_value,*c_value,temp;

 is_a=is_b=is_c=is_d=0;
 a_value=b_value=c_value=NULL;
 
 if(argc==1) 
  {
        fprintf(stderr,"Usage:%s [-a value] [-b value] [-c value] [-d] arglist ...\n", argv[0]);
        exit(1);
   }

 while((temp=getopt(argc,argv,"a:b:c:d"))!=-1)
  {
     switch (temp) 
   {
   case 'a':
is_a=1;
a_value=optarg;
        break;
   case 'b':
is_b=1;
b_value=optarg;
break;
   case 'c':
is_c=1;
c_value=optarg;
break;
   case 'd':
is_d=1;
break;
  }
   }

 printf("Option has a:%s with value:%s\n",is_a?"YES":"NO",a_value);
 printf("Option has b:%s with value:%s\n",is_b?"YES":"NO",b_value);
 printf("Option has c:%s with value:%s\n",is_c?"YES":"NO",c_value);
 printf("OPtion has d:%s\n",is_d?"YES":"NO");
 i=optind;
   while(argv[i]) printf(" with arg:%s\n",argv[i++]);
 exit(0);
}  

getopt_long比getopt复杂一点,不过用途要比getopt广泛.struct option 指出我们可以接受的附加参数选项. 
name:指出长选项的名称(如我们的option1) 
has_flag:为0时表示没有参数值,当为1的时候表明这个参数选项要接受一个参数值.为2时表示参数值可以有也可以没有. 
指出函数的返回值.如果为NULL,那么返回val,否则返回0.并将longindex赋值为选项所在数组(longopts)的位置. 

/* 这个实例是从 GNU Libc 手册上看到的 */

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>


int main (int argc, char **argv)
{
  int c;

  while (1)
    {
      struct option long_options[] =
        {
          {"add", 1, 0, 0},
          {"append", 0, 0, 0},
          {"delete", 1, 0, 0},
/* 返回字符c,等同于 -c 选项 */
          {"create", 0, 0, 'c'},
          {"file", 1, 0, 0},
/* 数组结束 */
          {0, 0, 0, 0}
        };
      /* getopt_long stores the option index here. */
      int option_index = 0;

      c = getopt_long (argc, argv, "abc:d:",
                       long_options, &option_index);

      /* Detect the end of the options. */
      if (c == -1)
        break;

      switch (c)
        {
        case 0:
          printf ("option %s", long_options[option_index].name);
          if (optarg)
            printf (" with arg %s\n", optarg);
          break;

        case 'a':
          puts ("option -a\n");
          break;

        case 'b':
          puts ("option -b\n");
          break;

/* 可能是-c --creat参数指出来的 */
        case 'c':
          printf ("option -c with value `%s'\n", optarg);
          break;

        case 'd':
          printf ("option -d with value `%s'\n", optarg);
          break;
        }
    }

  exit (0);
}

当我们输入了错误的选项后,系统会给出错误的提示,如果我们想屏蔽这个信息,我们可以设置opterr为0,对于错误的选项,函数分析时候返回一个'?'字符.我们可以自己对这个字符进行处理. 

 

-----------------------------------------------

象xxx -h host --password 123456这种命令,编程时,如何方便的取得命令行参数?有一个很好的方法,就是调用getopt()。

函数定义:
#include
int getopt(int argc, char * const argv[],
        const char *optstring);

extern char *optarg;
extern int optind, opterr, optopt;


#define _GNU_SOURCE
#include

int getopt_long(int argc, char * const argv[],
        const char *optstring,
        const struct option *longopts,
        int *longindex);

int getopt_long_only(int argc, char * const argv[],
        const char *optstring,
        const struct option *longopts,
        int *longindex);


getopt()函数是用来解析命令行参数的。这里,主要解释getopt_long()。

    getopt_long()的头两参数,argc和argv分别是传递给main()的参数的个数和参数数组(和main()的argc和argv是一个概念)。

    getopt_long()中,optstring是一个字符串,表示可以接受的参数。例如,"a:b:cd",表示可以接受的参数是a,b,c,d,其中,a和b参数后面

跟有更多的参数值。(例如:-a host --b name)

    getopt_long()中,参数longopts,其实是一个结构的实例:
struct option {
  const char *name;
    //name表示的是长参数名
  int has_arg;
    //has_arg有3个值,no_argument(或者是0),表示该参数后面不跟参数值
    //   required_argument(或者是1),表示该参数后面一定要跟个参数值
    //   optional_argument(或者是2),表示该参数后面可以跟,也可以不跟参数值
  int *flag;
    //用来决定,getopt_long()的返回值到底是什么。如果flag是null,则函数会返回与该项option匹配的val值
  int val;
    //和flag联合决定返回值
}

给个例子:

struct option long_options[] = {
  {"a123",       required_argument,      0, 'a'},
  {"c123",       no_argument,            0, 'c'},
}

现在,如果命令行的参数是-a 123,那么调用getopt_long()将返回字符'a',并且将字符串123由optarg返回(注意注意!字符串123由optarg带

回!optarg不需要定义,在getopt.h中已经有定义)
那么,如果命令行参数是-c,那么调用getopt_long()将返回字符'c',而此时,optarg是null。

最后,当getopt_long()将命令行所有参数全部解析完成后,返回-1。

看来,我说的有点混乱,那么,看个例子,我相信,代码最能说明问题:

#include
#include
#include
#include

int main( int argc, char **argv )
{

 struct option long_options[] = {
   {"a123",       required_argument,      0, 'a'},
   {"c123",       no_argument,            0, 'c'},
 }
 int opt;
 
 printf("starting... ");
 
 while((opt = getopt_long(argc, argv, "a:c", long_options, NULL)) != -1)
 {
  switch (opt)
  {
  case 'a':
    printf("It's a! ");
    printf("string of a:%s ",optarg);
  break;
   
  case 'c':
    printf("It's c! ");
  break;
   
  default:
    printf("You should look for help! ");
    exit(1);
  break;           
  }
 }
 printf("end... ");
 return 0;
}

编译后,假设生成a.out,可以试验一下。
./a.out -a hello -c
输出:
starting...
It's a!
string of a:hello
It's c!
end...

这个程序不难,一下子就能看明白。