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;
}
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);
}