公 告

欢迎各位网友添加友情链接,在您添加本博客:http://linux0818.blogspot.com/ 做为链接后, E-mail:linux0818@gmail.com给我,我将将您的网址添加到本博客。

2008年12月16日星期二

GNU 长选项命令解析--getopt_long()

Linux系统下,需要大量的命令行选项,如果自己手动解析他们的话实在是有违软件复用的思想,不过还好,GNU C
library留给我们一个解析命令行的接口(X/Open规范),好好使用它可以使你的程序改观不少。

使用getopt_long()需要引入头文件

#include <getopt.h>

现在我们使用一个例子来说明它的使用。

一个应用程序需要如下的短选项和长选项。

短选项 长选项 作用

-h --help 输出程序命令行参数说明然后退出
-c filename --cat filename 给定显示文件名
-v --version 显示程序当前版本后退出

为了使用getopt_long函数,我们需要先确定两个结构:

1.一个字符串,包括所需要的短选项字符,如果选项后有参数,字符后加一个":"符号。本例中,这个字符串应该为"hc:v"。(因为-o后面有参数filename,所以字符后面要加":")

2.一个包含长选项字符串的结构体数组,每一个结构体包含4个域,第一个域为长选项字符串,第二个域是一个标识,只能为0或1,分别代表没有、有。第三个域永远为NULL。第四个域为对应的短选项字符串。结构体数组的最后一个元素全部为NULL和0,标识结束。在本例中,它应该像一下的样子:

const struct option long_options[] = {
{ "help", 0, NULL, 'h' },
{ "cat", 1, NULL, 'c' },
{ "version", 0, NULL, 'v' },
{ NULL, 0, NULL, 0}
};

调用时需要把main的两个参数argc和argv以及上述两个数据结构传给getopt_long。

每次调用getopt_long,它会解析一个符号,返回相应的短选项字符,如果解析完毕返回-1。所以需要使用一个循环来处理所有的参数,而相应的循环里会使用switch语句进行选择。如果getopt_long遇到一个无效的选项字符,它会打印一个错误消息并且返回'?',很多程序会打印出帮助信息并且中止运行;当getopt_long解析到一个长选项并且发现后面没有参数则返回':',表示缺乏参数。当处理一个参数时,全局变量optarg指向下一个要处理的变量。当getopt_long处理完所有的选项后,全局变量optind指向第一个未知的选项索引。

这一个例子代码为下:

/*-----------------------------------------------------------------------

文件名:getopt_long.c

编译环境: Ubuntu6.10, gcc

功能: 对可执行文件的参数的长短选项的解析.

_____________________________________________*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>

#define FLAG_VERSION (1<<0)
#define FLAG_HELP (1<<1)
#define FLAG_LS (1<<2)
#define FLAG_CAT (1<<4)
#define VERSION "1.01"

struct opt {
unsigned int flags;
char *filename;
};
struct opt opt;

/* Return -1 on error, 0 on success */
int parse_cmd_line(int argc, char *const argv[])
{
int option;
const char *optstring = "hlc:v?";
struct option longopts[] = {
{"cat", required_argument, NULL, 'c'},
{"ls", no_argument, NULL, 'l'},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{0, 0, 0, 0}
};

while ((option =
getopt_long(argc, argv, optstring, longopts, NULL)) != -1)
switch (option) {
case 'c':
opt.flags |= FLAG_CAT;
opt.filename = optarg;
break;
case 'h':
opt.flags |= FLAG_HELP;
break;
case 'l':
opt.flags |= FLAG_LS;
break;
case 'v':
opt.flags |= FLAG_VERSION;
break;
case '?':
opt.flags |= FLAG_HELP;
return -1;
}

if ((opt.flags & FLAG_CAT) && (opt.filename == NULL)) {
return -1;
}

return 0;
}

void print_help(void)
{
static const char *help =
"Usage: getopt_long [OPTIONS]\n"
"Options are:\n"
" -c, --cat Get one file content (Format: getopt_long -c
/etc/password)\n"
" -l, --ls Get current directory's file and directory\n"
" -h, --help Display this help text and exit\n"
" -v, --version Display the version and exit\n";
printf("%s", help);
}

int main(int argc, char **argv)
{
char par[128] = "";

if (argc < 2) {
print_help();
exit(0);
}

opt.flags = 0;

if (parse_cmd_line(argc, argv) < 0) { // parse command line.
exit(-1);
}

if (opt.flags & FLAG_HELP) { // get 'help' .
print_help();
exit(0);
}

if (opt.flags & FLAG_VERSION) { // get version of soft.
printf("Soft Version:%s\n", VERSION);
exit(0);
}

if (opt.flags & FLAG_CAT) { // 'cat' a file
sprintf(par, "%s%c%s", "cat", ' ', opt.filename);
system(par);
exit(0);
}

if (opt.flags & FLAG_LS) { // 'ls' current directory
system("ls -l");
exit(0);
}

return 0;
}

编译: gcc -o getopt_long getopt_long.c

---------------------------------------------------------------------------

运行:

./getopt_long -c /etc/passwd

结果:

root:x:0:0:root:/root:/bin/bash
setup:x:0:0:root:/:/usr/sbin/setup
nobody:x:99:99:Nobody:/:
squid:x:100:100:Squid user:/:
snort:x:101:101:Snort user:/:
sshd:x:102:102:SSH user:/:
ntpd:x:103:103:NTPD user:/:
imspector:x:104:104:IMSpector user:/:
clam:x:105:105:Clam user:/:
sip:x:106:106:SIP user:/:
mysql:x:107:107:MySQL user:/:
---------------------------------------------------------------------------

运行: ./getopt_long -v

结果: Soft Version:1.01

---------------------------------------------------------------------------

如果要运行长选项也是一样的结果,如:

./getopt_long --cat /etc/passwd

./getopt_long --ls

./getopt_long --version


--
/**************************************/
Name: Xiong Feng
E-mail:linux0818@gmail.com
MSN:linux0818@hotmail.com
QQ:23562033
Address: GuangZhou.China
/**************************************/

没有评论:

发表评论