使用场景
在Linux中,输入命令"ls -al",可以显示指定工作目录下的内容。
-a 显示所有文件及目录 (. 开头的隐藏文件也会列出)
-l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出
"-al"是选项,那这个选项是怎么被识别的呢?就和getopt这个函数相关。
getopt可以用来解析命令的选项,以及选项的参数。"ls -al /home"中"-al"是选项,"/home"是参数。
getopt
#include <getopt.h> // man里说是#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
参数
argc —— 提供给主函数的参数个数
argv —— 参数的字符串数组的指针
optstring —— 由三部分组成,第一部分是可选的字符’+‘或’-’,第二部分是一个可选的字符’:’,第三部分是具体的选项字符串。
1. 单个字符:表示选项后不带参数。
2. 单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。
3. 单个字符后跟两个冒号:表示该选项后可以跟一个参数,也可以不跟。如果跟一个参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。如果没有跟参数,则optarg = NULL。
举例说明
第三部分 “ab:c::d:e”
abcde 分别是选项字符,选项字符其后跟 “:” 表示该选项有参数,选项跟参数之间可有空格,也可没有空格,选项字符后跟 “::” 表示参数可有可无,但如果有参数选项和参数之间不能有空格,选项字符后不跟 “:” 或 “::” 表示该选项没参数。"-ae -b100 -c -d 200"就是一个对应于上述 optstring 的命令选项,没参数的选项可以写在一起,比如 -ae。
getopt() 默认情况下会改变参数的顺序,从而使 nonoption argv-element 移至所有选项之后,但如果 optstring 第一部分是字符 ‘+’,或者设置了环境变量POSIXLY_CORRECT,第一个 nonoption argv-element 出现时立即停止选项处理,例如 “+ab:c::d:e”,"-ae 100 -c -d 200" 中 100 及其以后的参数都不再作为选项处理。
如果第一部分是 ‘-’,每个 nonoption argv-element 作为选项 1 的参数,这里的 1 是数字 1 不是字符 1。
如果第二部分的 ‘:’ 存在,当丢失选项参数时 getopt() 不再返回 ‘?’ 而是返回 ‘:’,且不会打印出错信息。
返回值
如果选项成功找到,返回选项字符;
如果所有命令行选项都解析完毕,返回 -1;
如果遇到选项字符不在 optstring 中,返回字符 ‘?’,并将 optopt 置为该选项字符;
如果遇到丢失参数,返回 ‘?’ 或 ‘:’,当返回返回 ‘?’ 时且 opterr 非 0 会提示错误信息。
optarg —— 指向当前选项参数(如果有)的指针或NULL(无参数)。
optind —— 再次调用 getopt() 时下一个 argv-element 的索引。
optopt —— 最后一个未知选项。
opterr —— 是否希望 getopt() 向 stderr 打印出错信息,0 为不打印,opterr 默认非0。
案例
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ch;
char *seg1, *seg2, *seg3;
//如果 'n' 没有冒号 ':', 则 optarg 为 (null)
//如果 'n' 有冒号 ':', 则 optarg 为 第一个选项
//下面有运行结果
while((ch = getopt(argc,argv,"n:"))!= -1)
{
switch(ch)
{
case 'n': //n为name开头字母
seg1=optarg;
seg2=argv[optind];
seg3=argv[optind+1];
printf("option's seg1: +%s\n",seg1);
printf("option's seg2: +%s\n",seg2);
printf("option's seg3: +%s\n",seg3);
break;
default:
printf("unrecongnized option :%c\n",ch);
break;
}
}
return 0;
}
输入命令
./optget_test -n Jack Mike Bob
运行结果('n'有冒号':')
option's seg1: +Jack
option's seg2: +Mike
option's seg3: +Bob
运行结果('n'没有冒号':')
option's seg1: +(null)
option's seg2: +Jack
option's seg3: +Mike
getopt_long
#include <getopt.h>
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
int getopt_long(int argc, char * const argv[], const char *optstring,
const struct option *longopts, int *longindex);
option 的struct成员意义如下:
name:长选项的名字。
has_arg:no_argument (or 0) 选项没有参数;required_argument (or 1) 选项有一个参数ment; optional_argument (or 2) 选项可有可无参数。
flag:标识结果如何返回。选项如果被找到,如果 flag 是 NULL,getopt_long() 将会返回 val,否则 getopt_long() 返回 0,而且 *flag 被设置为 val;选项如果未被找到,getopt_long() 返回 ‘?’,*flag(如果 flag 不为 NULL ) 保持不变。
val:标识返回值。
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for exit */
#include <getopt.h> /* for getopt_long_only */
static struct option long_options[] = {
{"add", required_argument, 0, 'a' },
{"sub", required_argument, 0, 's' },
{"mul", required_argument, 0, 'm' },
{"div", required_argument, 0, 'd' },
{"help",no_argument, 0, 'h' },
{0, 0, 0, 0 },
};
int main(int argc, char **argv)
{
char ch;
int val[2];
int res;
int option_index = 0;
while((ch = getopt_long(argc, argv, "a:s:m:d:h",
long_options, &option_index)) != -1)
{
switch(ch)
{
case 'a':
sscanf(optarg, "%d", &val[0]);
sscanf(argv[optind], "%d", &val[1]);
res = val[0] + val[1];
printf("%d + %d = %d\n", val[0], val[1], res);
break;
case 's':
sscanf(optarg, "%d", &val[0]);
sscanf(argv[optind], "%d", &val[1]);
res = val[0] - val[1];
printf("%d - %d = %d\n", val[0], val[1], res);
break;
case 'm':
sscanf(optarg, "%d", &val[0]);
sscanf(argv[optind], "%d", &val[1]);
res = val[0] * val[1];
printf("%d * %d = %d\n", val[0], val[1], res);
break;
case 'd':
sscanf(optarg, "%d", &val[0]);
sscanf(argv[optind], "%d", &val[1]);
res = val[0] / val[1];
printf("%d / %d = %d\n", val[0], val[1], res);
break;
case 'h':
printf("commend list:\n");
printf("-add [value1] [value2]: add\n");
printf("-sub [value1] [value2]: subtract\n");
printf("-mul [value1] [value2]: multiply\n");
printf("-div [value1] [value2]: divide\n");
printf("-help\n");
break;
default:
break;
}
}
exit(EXIT_SUCCESS);
}
getopt_long_only
#include <getopt.h>
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
int getopt_long_only(int argc, char * const argv[], const char *optstring,
const struct option *longopts, int *longindex);
option 的struct成员意义如下:
name:长选项的名字。
has_arg:no_argument (or 0) 选项没有参数;required_argument (or 1) 选项有一个参数ment; optional_argument (or 2) 选项可有可无参数。
flag:标识结果如何返回。选项如果被找到,如果 flag 是 NULL,getopt_long() 将会返回 val,否则 getopt_long() 返回 0,而且 *flag 被设置为 val;选项如果未被找到,getopt_long() 返回 ‘?’,*flag(如果 flag 不为 NULL ) 保持不变。
val:标识返回值。
案例
#include <stdio.h> /* for printf */
#include <stdlib.h> /* for exit */
#include <getopt.h> /* for getopt_long_only */
static struct option long_options[] = {
{"add", required_argument, 0, 'a' },
{"sub", required_argument, 0, 's' },
{"mul", required_argument, 0, 'm' },
{"div", required_argument, 0, 'd' },
{"help",no_argument, 0, 'h' },
{0, 0, 0, 0 },
};
int main(int argc, char **argv)
{
char ch;
int val[2];
int res;
int option_index = 0;
while((ch = getopt_long_only(argc, argv, "a:s:m:d:h",
long_options, &option_index)) != -1)
{
switch(ch)
{
case 'a':
sscanf(optarg, "%d", &val[0]);
sscanf(argv[optind], "%d", &val[1]);
res = val[0] + val[1];
printf("%d + %d = %d\n", val[0], val[1], res);
break;
case 's':
sscanf(optarg, "%d", &val[0]);
sscanf(argv[optind], "%d", &val[1]);
res = val[0] - val[1];
printf("%d - %d = %d\n", val[0], val[1], res);
break;
case 'm':
sscanf(optarg, "%d", &val[0]);
sscanf(argv[optind], "%d", &val[1]);
res = val[0] * val[1];
printf("%d * %d = %d\n", val[0], val[1], res);
break;
case 'd':
sscanf(optarg, "%d", &val[0]);
sscanf(argv[optind], "%d", &val[1]);
res = val[0] / val[1];
printf("%d / %d = %d\n", val[0], val[1], res);
break;
case 'h':
printf("commend list:\n");
printf("-add [value1] [value2]: add\n");
printf("-sub [value1] [value2]: subtract\n");
printf("-mul [value1] [value2]: multiply\n");
printf("-div [value1] [value2]: divide\n");
printf("-help\n");
break;
default:
break;
}
}
exit(EXIT_SUCCESS);
}
getopt_long和getopt_long_only区别
getopt_long 支持的 --add 1 2 \ -a 1 2
getopt_long_only 支持的 -add 1 2 \ --add 1 2 \ -a 1 2 \ --a 1 2