浅析getopt()与getopt_long()与getopt_long_only()

因为最近在linux上实现ls这个linux上最常用的命令(当然了,只涉及简单几个命令而已),所以就遇到了如何获取参数这个问题,学长说可以用getopt()这个函数来获取,所以就查了查,说实话这个函数乍一看真看不懂咋用,反正我是从昨天下午查到今天下午,不过还好好,现在会简单的应用了。接下来我试着简单明了的说说咋用,希望初学者一看就会用。

我的my_ls源代码地址:https://github.com/gaopu/my_ls


它们的作用:

获取程序运行时用户输入的参数


什么是参数:

例如运行ls时输入的-a,-l,这些就是参数,还有一种长参数例如--help,-help。


为什么是三个函数:
因为这三个函数的分工不同:
getopt()是获取短参数的,它可以获取-a,-l类型的短参数,也可以-al合并的获取到a和l
getopt_long()是在getopt()的基础上获取长参数,它还可以获取--help这种参数

getopt_long_only()也是在上一个函数基础上有所增加,输入长参数可以不用输入两个--,而是这样:-help


函数原型:
下面这个函数在#include <unistd.h>中
int getopt(int argc, char * const argv[],const char *optstring)

下面这两个函数在 #include <getopt.h>中
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():

我感觉直接上例子能更快上手使用,那就拿ls 这个例子来写一个获取参数的循环:

	//录入参数
	char opt;
	opterr = 0;			//不显示参数错误信息
	while ((opt = getopt(argc,argv,"alRtS")) != -1) {
		if (opt == 'a') {
			param |= PARAM_a;
		} else if (opt == 'l') {
			param |= PARAM_l;
		} else if (opt == 'R') {
			param |= PARAM_R;
		} else if (opt == 'S') {
			param |= PARAM_S;
		} else if (opt == 't') {
			param |= PARAM_t;
		} else {
			printf("对不起,目前只支持参数R,S,a,t和l.\n");
			exit(0);
		}
	}


从这个例子来看如何使用,getopt()的牵连个参数是传给main()函数的argc和argv,最后一个是你要接收的参数,想接收什么字母,就把那个字符添加进去即可。这个函数如果读取结束会返回-1,所以检测是不是-1就可以了,不是就继续检测其他参数。还有,与获取参数有关的全局变量有:
optind 指向下一个扫描的位置
opterr 是否显示错误信息
optopt 读取到的字符如果不在opstring(上面例子是"alRtS")中,则存入optopt中。
optarg 存储选项的参数(下面这个例子会提到)

这些参数是实现定义好的,直接在程序中使用就好了,一般都是将opterr设置为0,使它不打印错误信息。


getopt_long():
来一个man手册给的完整例子:
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>


int main(int argc, char **argv)
{
   int c;
   int digit_optind = 0;
   int this_option_optind = optind ? optind : 1;
   int option_index = 0;


   static struct option long_options[] = {
	   {"add",     required_argument, 0,  0 },
	   {"append",  no_argument,       0,  0 },
	   {"delete",  required_argument, 0,  0 },
	   {"verbose", no_argument,       0,  0 },
	   {"create",  required_argument, 0, 'c'},
	   {"file",    required_argument, 0,  0 },
	   {0,         0,                 0,  0 }
   };


   while (1) {
	   c = getopt_long_only(argc, argv, "abc:d:012",
				long_options, &option_index);
	   if (c == -1)
		   break;


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


	   case '0':
	   case '1':
	   case '2':
		   if (digit_optind != 0 && digit_optind != this_option_optind)
			 printf("digits occur in two different argv-elements.\n");
		   digit_optind = this_option_optind;
		   printf("option %c\n", c);
		   break;


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


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


	   case 'c':
		   printf("option c with value '%s'\n", optarg);
		   break;


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


	   case '?':
		   break;


	   default:
		   printf("?? getopt returned character code 0%o ??\n", c);
	   }
   }


   if (optind < argc) {
	   printf("optind:%d\n",optind);
	   printf("non-option ARGV-elements: ");
	   while (optind < argc)
		   printf("%s ", argv[optind++]);
	   printf("\n");
   }


   exit(EXIT_SUCCESS);
}
这个例子中首先先看getopt_long()的第三个参数是"abc:d:012",这里的一个冒号代表这个冒号前面这个字符出现时需要有参数,例如这样ls -a5,那个这个5就是一个参数,虽然这个ls没这么用的,这里出现时举个例子,参数会存储在optarg这个变量中,也是事先定义好的,不用自己定义,直接用就可以了。

这个c:代表选项c后面必须跟一个参数。d:同样的意思。


如果是这样---->"c::"那么就是说c可以带参数也可以不带


说完了第三个参数,再说第四个参数:这个参数代表的是“长选项表”,传给它的是一个一维结构体数组名,其中每个结构体的定义是下面这样的
struct option
{
               const char *name;
               int         has_arg;
               int        *flag;
               int         val;
};
解释:

name长选项的名字


has_arg如果选项没有参数这一项是no_argument或者0;如果有参数那么是required_argument或者1;

如果参数是可选的是optional_argument或者2


flag如果为NULL,getopt_long()返回该结构val字段中的数值;如果不为NULL,getopt_long()会使得flag所指向变量中填入val字段中的数值,并且getopt_long()返回0;通常flag设置为NULL,val设置为与该长选项对应的短选项


val一个值,一般写成长选项所对应的短选项


下面来个具体的例子

               static struct option long_options[] = {
                   {"add",     required_argument, 0,  'a' },
                   {"delete",  required_argument, 0,  'd' },
                   {"verbose", no_argument,       0,  'v' },
                   {"create",  required_argument, 0, 'c'},
                   {"file",    required_argument, 0,  'f' },
               };




这样写的话那么如果输入--add那么函数会返回a,用一个char变量接收然后就可以在switch中判断参数进行处理了。

还有最后一个参数longindex,这个参数如果传的不是NULL,那么就指向一个具体的int变量,每次调用getopt_long()将会把长选项在longopts中的索引值存入longindex,例如长选项是--delete,那么这个参数就会被设置为1。


getopt_long_only()
这个用法和上面的getopt_long完全一样,就是在输入长选项的时候可以不用输入--而使用-

你可能感兴趣的:(浅析getopt()与getopt_long()与getopt_long_only())