getopt函数可以用来非常方便的处理命令行参数。函数的原型是:
int getopt(int argc, char * const argv[], const char *optstring);
以下是关键点:
1. argc, argv就是main函数的那两个。optstring是我们给出的格式字符串,特别的是格式字符串中的:表示该command option后面是有一个value的,比如:./xtop -n 20 -i 2 1111,在这里optstring就可以写成"n:i:",这表示n和i这两个是command option,而且这两个option后面都需要给value,如果没有:,就表示该option后面不需要value。有关optstring还有一些 约定,比如以+开头就有特殊含义,具体看man 3 getopt了。
2. 返回值。正常情况下,返回的是一个char,表示当前分析到的option字母,这样,下面就可以用一个switch来处理了。全部分析完毕后,返回 -1。如果碰到一个没有出现在optstring中的option,那么,getopt返回?(默认情况下)。其实不用这么麻烦,一般coding的时 候,将我们需要处理的option字母全部列出来以后,然后用一个default就可以将其他任何getopt的返回值视为非法,打印:Usage: xxxx这样的字符串,程序退出即可。
3. 注意点:出现在optstring中的我们指定的那些option不是强制的。比如说,上面例子中,我们要求-n, -i这两个option都是必须要设置的,而用户在执行程序的时候只给出了一个-n,那么,getopt是管不了这个事的。他只是呆板的从头往后分析以- 打头的token,然后给我们返回option字母。所以,对于这种情况,我们要自己在程序中检测用户是否对我们强制要求的option都设置了,否则, 就报错。事实上,按照option和argument的原理来说,option应该都是可选的,不然怎么叫optiton呢?应该把强制要求用户设置的全 部变成argument,这样是最符合逻辑的。
4. 前面说了,对于-n 20这样的option,getopt返回的是n这个字母,然后这个20怎么取到呢?getopt将option的value放在了一个全局变量中,名字 为optarg,类型是char *。我们通过访问optarg就可以取到这个value了。如果用户写的option是-n2,那么,getopt返回n,同时optarg的值是 -n2,这里也是需要我们手工判断的。除非用户写的是-n,后面没了,此时按照optstring中的要求,getopt会打印出错信息,同时返回?。
5. 最后,关于argument。也就是getopt分析完了所有的option之后,最后剩下的就是argument了。在上面的例子中,./xtop -n 20 -i 2 1111,这个最后的1111就是argument了。getopt会设置全局变量optind(类型是int),这个optind就是第一个 argument(也就是不以-打头的token,同时也不是option value的token)在argv数组中的index,也就是说,argv[optind]就可以取出这个argument。非常方便吧。这样,由于有 了这个optind,所以,事实上,用户在写命令行的时候就可以很自由了,可以将option混着写,也可以将argument和option混着写,不 用一定要把argument放在命令行的最后。
基本上注意点就是这些,附上xtop中的相关代码。getopt还有一些特殊的说明和feature,在man 3 getopt中都可以找到。此外,还有getopt_long这样的函数,可以用来handle --打头的长option,这个在man手册中也有说明。
int getopt(int argc, char * const argv[], const char *optstring);
以下是关键点:
1. argc, argv就是main函数的那两个。optstring是我们给出的格式字符串,特别的是格式字符串中的:表示该command option后面是有一个value的,比如:./xtop -n 20 -i 2 1111,在这里optstring就可以写成"n:i:",这表示n和i这两个是command option,而且这两个option后面都需要给value,如果没有:,就表示该option后面不需要value。有关optstring还有一些 约定,比如以+开头就有特殊含义,具体看man 3 getopt了。
2. 返回值。正常情况下,返回的是一个char,表示当前分析到的option字母,这样,下面就可以用一个switch来处理了。全部分析完毕后,返回 -1。如果碰到一个没有出现在optstring中的option,那么,getopt返回?(默认情况下)。其实不用这么麻烦,一般coding的时 候,将我们需要处理的option字母全部列出来以后,然后用一个default就可以将其他任何getopt的返回值视为非法,打印:Usage: xxxx这样的字符串,程序退出即可。
3. 注意点:出现在optstring中的我们指定的那些option不是强制的。比如说,上面例子中,我们要求-n, -i这两个option都是必须要设置的,而用户在执行程序的时候只给出了一个-n,那么,getopt是管不了这个事的。他只是呆板的从头往后分析以- 打头的token,然后给我们返回option字母。所以,对于这种情况,我们要自己在程序中检测用户是否对我们强制要求的option都设置了,否则, 就报错。事实上,按照option和argument的原理来说,option应该都是可选的,不然怎么叫optiton呢?应该把强制要求用户设置的全 部变成argument,这样是最符合逻辑的。
4. 前面说了,对于-n 20这样的option,getopt返回的是n这个字母,然后这个20怎么取到呢?getopt将option的value放在了一个全局变量中,名字 为optarg,类型是char *。我们通过访问optarg就可以取到这个value了。如果用户写的option是-n2,那么,getopt返回n,同时optarg的值是 -n2,这里也是需要我们手工判断的。除非用户写的是-n,后面没了,此时按照optstring中的要求,getopt会打印出错信息,同时返回?。
5. 最后,关于argument。也就是getopt分析完了所有的option之后,最后剩下的就是argument了。在上面的例子中,./xtop -n 20 -i 2 1111,这个最后的1111就是argument了。getopt会设置全局变量optind(类型是int),这个optind就是第一个 argument(也就是不以-打头的token,同时也不是option value的token)在argv数组中的index,也就是说,argv[optind]就可以取出这个argument。非常方便吧。这样,由于有 了这个optind,所以,事实上,用户在写命令行的时候就可以很自由了,可以将option混着写,也可以将argument和option混着写,不 用一定要把argument放在命令行的最后。
基本上注意点就是这些,附上xtop中的相关代码。getopt还有一些特殊的说明和feature,在man 3 getopt中都可以找到。此外,还有getopt_long这样的函数,可以用来handle --打头的长option,这个在man手册中也有说明。
int main(int argc, char *argv[])
{
int opt;
// argument handling
while ((opt = getopt(argc, argv, "n:i:o:")) != -1) {
switch(opt) {
case 'n':
if (!string_is_int(optarg)) {
fprintf(stderr, "Error: <times> should be an integer. Yours is %s\n", optarg);
goto FAILED;
}
check_times = atoi(optarg);
break;
case 'i':
if (!string_is_int(optarg)) {
fprintf(stderr, "Error: <time interval> should be an integer. Yours is %s\n", optarg);
goto FAILED;
}
check_interval = atoi(optarg);
break;
case 'o':
output_file = (char *)malloc(strlen(optarg) + 1);
if (output_file == NULL) {
fprintf(stderr, "Error: malloc for output file failed.\n");
goto FAILED;
}
strcpy(output_file, optarg);
break;
default:
printf("Usage: xtop -n <times> -i <time interval> [-o <output file>] <pid>\n");
goto FAILED;
}
}
// check whether the -n & -i are set
if (check_times <= 0 || check_interval <= 0) {
fprintf(stderr, "Usage: xtop -n <times> -i <time interval> [-o <output file>] <pid>\n");
fprintf(stderr, "Also make sure your <times>, <time interval> are positive integers.\n");
goto FAILED;
}
if (optind >= argc) {
fprintf(stderr, "Error: <pid> argument can't be found.\n");
goto FAILED;
}
if (!string_is_int(argv[optind])) {
fprintf(stderr, "Error: <pid> should be an integer. Yours is %s\n", argv[optind]);
goto FAILED;
}
pid = atoi(argv[optind]);
if (pid <= 0) {
fprintf(stderr, "Error: illegal <pid> argument. Pid should be a positive integer. Yours is %d\n", pid);
goto FAILED;
}
// -o <output file> is optional, so check whether the user set this
// xtop.out is the default output filename
if (output_file == NULL) {
printf("Begin analysing process %d, checking %d times after every %d seconds. Record results into xtop.out\n",
pid, check_times, check_interval);
} else {
printf("Begin analysing process %d, checking %d times after every %d seconds. Record results into %s\n",
pid, check_times, check_interval, output_file);
}
............
}
{
int opt;
// argument handling
while ((opt = getopt(argc, argv, "n:i:o:")) != -1) {
switch(opt) {
case 'n':
if (!string_is_int(optarg)) {
fprintf(stderr, "Error: <times> should be an integer. Yours is %s\n", optarg);
goto FAILED;
}
check_times = atoi(optarg);
break;
case 'i':
if (!string_is_int(optarg)) {
fprintf(stderr, "Error: <time interval> should be an integer. Yours is %s\n", optarg);
goto FAILED;
}
check_interval = atoi(optarg);
break;
case 'o':
output_file = (char *)malloc(strlen(optarg) + 1);
if (output_file == NULL) {
fprintf(stderr, "Error: malloc for output file failed.\n");
goto FAILED;
}
strcpy(output_file, optarg);
break;
default:
printf("Usage: xtop -n <times> -i <time interval> [-o <output file>] <pid>\n");
goto FAILED;
}
}
// check whether the -n & -i are set
if (check_times <= 0 || check_interval <= 0) {
fprintf(stderr, "Usage: xtop -n <times> -i <time interval> [-o <output file>] <pid>\n");
fprintf(stderr, "Also make sure your <times>, <time interval> are positive integers.\n");
goto FAILED;
}
if (optind >= argc) {
fprintf(stderr, "Error: <pid> argument can't be found.\n");
goto FAILED;
}
if (!string_is_int(argv[optind])) {
fprintf(stderr, "Error: <pid> should be an integer. Yours is %s\n", argv[optind]);
goto FAILED;
}
pid = atoi(argv[optind]);
if (pid <= 0) {
fprintf(stderr, "Error: illegal <pid> argument. Pid should be a positive integer. Yours is %d\n", pid);
goto FAILED;
}
// -o <output file> is optional, so check whether the user set this
// xtop.out is the default output filename
if (output_file == NULL) {
printf("Begin analysing process %d, checking %d times after every %d seconds. Record results into xtop.out\n",
pid, check_times, check_interval);
} else {
printf("Begin analysing process %d, checking %d times after every %d seconds. Record results into %s\n",
pid, check_times, check_interval, output_file);
}
............
}