天天看点

Linux程序设计-getopt处理命令行参数

Linux中,对于多数程序,都能够接受命令行选项,进行调用交互。具有可靠的复杂命令行参数处理机制,会使得程序健壮性更强,更好用。而getopt()是一个专门设计来处理命令行参数的库函数,简单而易用。

1.命令语法格式

命令的格式:

COMMAND OPTIONS ARGUMENT

命令 选项 参数

COMMAND:本次想要执行的操作,想要发起的进程

内部命令:也叫内建命令或内置命令,直接内建与shell的命令

外部命令:通过安装某些应用程序而安装的命令

OPTIONS:修正命令的执行效果的组成部分

短选项:

-CHAR

-a,-b,-i,…

某些特殊的命令还有特殊的短选项:

+CHAR

+C,…

当同时使用多个短选项时,可以将其合并书写,如:

-a -b -i <=>-abi

长选项:

–WORD

–help,–all,–verbose,–list,…

注意:当一个命令中同时有多个长选项时,不可以合并书写;

注意:

1、有些选项,其选项本身需要参数;

2、有些特殊的命令在写选项时,可以不写“-”;有些特殊的命令,在写选项时,一 定不能写“-”;

3、有些特殊命令的长选项,只能使用一个“-”;

ARGUMENT(PARAMETERS):此次执行命令的操作目标的对象

注意:1、有些命令无须写参数;

2、有些命令必须写参数;

3、有的命令必须写多个参数;

对于整个命令格式:

注意:1.在书写命令格式的时候,COMMAND、OPTIONS、AGUMENT之间必须使用至少一个空白字符进行间隔;

2.有些命令在执行的时候,OPTIONS和AGUMENT可以交换位置;

3.由于文件系统的限制,导致命令中的COMMAND部分、OPTIONS部分、AGUMRNT部分必须区分大小写;

2.基本的命令行处理技术

C 程序通过 argc 和 argv 参数访问它的命令行参数。argc 是整型数,表示参数的个数(包括命令名):

int main(int argc, char*argv[]) 
{
 	…… 
}
           

当 C 运行时库的程序启动代码调用 main() 时,已经对命令行进行了处理。argc 参数包含参数的计数值,而 argv 包含指向这些参数的指针数组。argv[0]是程序名。

3.命令行参数解析函数(短参数) —— getopt()

Linux下命令行解析函数getopt.

原型:

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

参数:

agrc:命令行参数个数

argv[]:命令行参数数组

optstring:命令行参数选项

getopt调用一次将返回第一个选项,再次调用将返回下一个选项并设置相应的全局变量,不再识别返回-1:

optarg–指向当前选项参数的指针

optind–成功调用一次指向下一个argv指针的索引

optopt–最后一个未知选项,默认为0,出错为出错时的选项

opterr–全局变量默认为1,控制错误信息的输出,改为0则不输出

optstring注意:a: b:c::e

a b c d e表示命令行的 -a -b -c -d -e选项; :和::表示选项后有参数,e后边并没有参数。

:参数在选项后有一个空格或者挨着; ::可省略参数或者参数紧挨着选项 。

#include<stdio.h>
#include<unistd.h>
#include<string.h>
 
//int opterr=0;//控制错误信息0表示关闭
int main(int argc,char *argv[]){
	int ch;
	printf("命令行参数个数:argc=%d\n",argc);
	
	for(int i=0;i<argc;i++){
		printf("命令行参数:argv[%d]=%s\n",i,argv[i]);
	}
	
	ch=getopt(argc,argv,"a:b::c:d");
	while(ch!=-1){
		switch(ch){
			case 'a':printf("选择a选项:ch=%c,optind=%d,optarg=%s,opterr=%d,optopt=%d\n",ch,optind,optarg,opterr,optopt);break;
			case 'b':printf("选择b选项:ch=%c,optind=%d,optarg=%s,opterr=%d,optopt=%d\n",ch,optind,optarg,opterr,optopt);break;
			case 'c':printf("选择c选项:ch=%c,optind=%d,optarg=%s,opterr=%d,optopt=%d\n",ch,optind,optarg,opterr,optopt);break;
			case 'd':printf("选择d选项:ch=%c,optind=%d,optarg=%s,opterr=%d,optopt=%d\n",ch,optind,optarg,opterr,optopt);break;
			case '?':printf("非法选项或者缺少参数:ch=%c,optind=%d,optarg=%s,opterr=%d,optopt=%d\n",ch,optind,optarg,opterr,optopt);break;
			default:printf("非法选项或者缺少参数返回?,等同于上边的?选项");break;
		}
		ch=getopt(argc,argv,"a:b::c:d");
	}
	return 0;
}
           
Linux程序设计-getopt处理命令行参数
Linux程序设计-getopt处理命令行参数
Linux程序设计-getopt处理命令行参数

4.长选项命令行解析-getopt_long()

UNIX 应用程序支持长选项,即一对短横线。

getopt_long() 是同时支持长选项和短选项的 getopt() 版本。GNU 提供了 getopt-long()和 getopt-long-only()函数支持长选项的命令行解析,其中,后者的长选项字串是以一个短横线开始的,而非一对短横线。下面是它们的声明:

#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_long()的前三个参数与上 面的 getopt()相同,第4个参数是指向 option 结构的数组,option 结构被称为“长选项表”。longindex:longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值,这可以用于错误诊断。

longopts:表示长选项结构体。结构如下:

struct option{
const char *name; int has_arg;
int *flag;
int val;
};
           

对结构中的各元素解释如下:

(1) const char *name—这是选项名,前面没有短横线。譬如"help"、"verbose"之类。

(2) int has_arg—描述了选项是否有选项参数。如果有,是哪种类型的参数,此时,它的值一定是下表中的一个。

符号常量 数值 含义
no_argument 选项没有参数
required_argument 1 选项需要参数
optional_argument 2 选项参数可选

(3) flag:这个参数有两个意思,空或者非空。

  • a:如果参数为空NULL,那么当选中某个长选项的时候,getopt_long将返回val值。
    eg,可执行程序 --help,getopt_long的返回值为h.             
               
  • b:如果参数不为空,那么当选中某个长选项的时候,getopt_long将返回0,并且将flag指针参数指向val值。
    eg: 可执行程序 --http-proxy=127.0.0.1:80 那么getopt_long返回值为0,并且lopt值为1。
               

(4) val:表示指定函数找到该选项时的返回值,或者当flag非空时指定flag指向的数据的值val。

返回值:

(1)如果短选项找到,那么将返回短选项对应的字符。

     (2)如果长选项找到,如果flag为NULL,返回val。如果flag不为空,返回0

     (3)如果遇到一个选项没有在短字符、长字符里面。或者在长字符里面存在二义性的,返回“?”

     (4)如果解析完所有字符没有找到(一般是输入命令参数格式错误,eg: 连斜杠都没有加的选项),返回“-1”

     (5)如果选项需要参数,忘了添加参数。返回值取决于optstring,如果其第一个字符是“:”,则返回“:”,否则返回“?”。
           

注意:

(1)longopts的最后一个元素必须是全0填充,否则会报段错误

    (2)短选项中每个选项都是唯一的。而长选项如果简写,也需要保持唯一性。
           

getopt_long() 解析参数用例(仅列出参数解析部分):

//程序调用命令格式:CollectionInfo [-c  config_file_name] [--systeminfo or -s] [--bootinfo or -b] [--rtinfo or -r]
int main(int argc, char *argv[])
{
	//C语言没有布尔类型,需要自定义布尔类型
	typedef int bool;
	#define true 1
	#define false 0
	//根据调用命令,定义变量,判断相应参数是否存在,存放对应参数值
	bool c_option = false;
	char *c_option_argv = NULL;
	bool s_option = false;
	bool b_option = false;
	bool r_option = false;
	//根据调用命令,创建参数结构体
	static struct option longopts[] ={
		{ "c", required_argument, NULL, 'c' },
		{ "systeminfo", no_argument, NULL, 's' },
		{ "bootinfo", no_argument, NULL, 'b' },
		{ "rtnfo", no_argument, NULL, 'r' },
		{ 0, 0, 0, 0},
	};
	//根据调用命令,创建命令短选项字符串
	char * optstring="c:sbr";
	int lpt;//定义变量,获取getopt_long()函数返回值
	while((lpt = getopt_long(argc, argv, optstring, longopts, NULL)) != -1){
	  switch(lpt) {
		  case 'c': {
			//-c 参数项存在,获取参数值
			c_option = true;
			c_option_argv =(char *) malloc(strlen(optarg)+1);
			strcpy(c_option_argv,optarg);
			c_option_argv[strlen(optarg)]='\0';
			break;
		  }
		  case 's':{
			//-s or --systeminfo该参数存在,将该变量值设为true
			s_option = true;
			break;
		  }
		  case 'b':{
			//-b or --bootinfo该参数存在,将该变量值设为true
			b_option = true;
			break;
		  }
		  case 'r':{
			//-r or --rtinfo该参数存在,将该变量值设为true
			r_option = true;
			break;
		  }
		default:
		  //解析参数错误
		  break;
		}
	}
	//......
	return 0;
}
           

官方给出测试用例:

#include <stdio.h>     /* for printf */
#include <stdlib.h>    /* for exit */
#include <getopt.h>
 
int
main(int argc, char **argv)
{
    int c;
    int digit_optind = 0;
 
   while (1) {
        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 }
        };
 
       c = getopt_long(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("non-option ARGV-elements: ");
        while (optind < argc)
            printf("%s ", argv[optind++]);
        printf("\n");
    }
 
   exit(EXIT_SUCCESS);
}
           

继续阅读