Linux下开发C程序,甚至是GUI程序,都可能需要处理复杂的命令行参数。健全、可靠的复杂命令行参数处理机制,可使程序方便使用,也更显专业。Linux下几乎所有的命令都提供了参数处理机制,包括短选项和长选项。
POSIX标准中对程序名、参数作了如下相关约定:
* 程序名不宜少于2个字符且不多于9个字符;
* 程序名应只包含小写字母和阿拉伯数字;
* 选项名应该是单字符活单数字,且以短横‘-‘为前綴;
* 多个不需要选项参数的选项,可以合并。(譬如:foo -a -b -c ---->foo -abc)
* 选项与其参数之间用空白符隔开;
* 选项参数不可选。
* 若选项参数有多值,要将其并为一个字串传进来。譬如:myprog -u "arnold,joe,jane"。这种情况下,需要自己解决这些参数的分离问题。
* 选项应该在操作数出现之前出现。
* 特殊参数‘--'指明所有参数都结束了,其后任何参数都认为是操作数。
* 选项如何排列没有什么关系,但对互相排斥的选项,如果一个选项的操作结果覆盖其他选项的操作结果时,最后一个选项起作用;如果选项重复,则顺序处理。
* 允许操作数的顺序影响程序行为,但需要作文档说明。
* 读写指定文件的程序应该将单个参数'-'作为有意义的标准输入或输出来对待。
GNU鼓励程序员使用--help、--verbose等形式的长选项。这些选项不仅不与POSIX约定冲突,而且容易记忆,另外也提供了在所有GNU工具之间保持一致性的机会。
GNU长选项有自己的约定:
* 对于已经遵循POSIX约定的GNU程序,每个短选项都有一个对应的长选项。
* 额外针对GNU的长选项不需要对应的短选项,仅仅推荐要有。
* 长选项可以缩写成保持惟一性的最短的字串。
* 选项参数与长选项之间或通过空白字符活通过一个'='来分隔。
* 选项参数是可选的(只对短选项有效)。
* 长选项允许以一个短横线为前缀。
C程序通过argc和argv参数访问它的命令行参数,通过main()函数调用和处理:int main(int argc, char *argv[])。一般情况下,我们事先约定好参数的顺序位置,然后在main函数中进行简单处理。这种方式实现比较简单,然后用户使用起来很不方便,Linux下的各种工具的命令行参数可以是不分先后次序的。幸运的是,Linux为C程序员提供了相关的命令行参数解析函数:getopt()和getopt_long(),分别用于处理短选项和长选项,当然后者可以同时处理短、长选项。函数原型如下:
#include <unistd.h>
int getopt(int argc, char * const argv[], const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
getopt() 函数是一个标准库调用,可允许使用直接的 while/switch 语句方便地逐个处理命令行参数和检测选项(带或不带附加的参数)。getopt_long() 允许在几乎不进行额外工作的情况下处理更具描述性的长选项,非常受开发人员的欢迎。下面用笔者开发的一个Daemon程序wsiod中的参数处理来说明具体的处理过程。wsiod参数帮助信息如下:
[liuag] /home/liuag/workspace/WSIO/WSIO-1.3/server > ./wsiod --help
Usage: wsiod [OPTION]
WSIO server based on web service.
Mandatory arguments to long options are mandatory for short options too.
-h, --host hostname in soap_bind, default is host which the service runs
-p, --port port which the sercer runs on, default is 8080
-b, --backlog request backlog, default is 100
-t, --type server type, default is COMMON
-k, --keepalive attempt to keep socket connections alive
-c, --chunk use HTTP chunking
-d, --dime use DIME encoding
-D, --debug print debug info
--help print this help
Server type:
COMMON the simplest server
STANDALONE stand-alone server, which can run on port 80
MULTITHREAD multi-thread stand-alone server
POOL using a pool of servers
QUEUE using a queue of requests for server
GSI prethreaded server with GSI enabled
Report bugs to <Aigui.LIU@ihep.ac.cn>.
wsiod参数处理实现C程序段如下:
#include <unistd.h>
#include <getopt.h>
enum SERVERTYPE{COMMON, STANDALONE, MULTITHREAD, POOL, QUEUE, GSI};
int keepalive = 0, dime = 0, chunk = 0;
/* WSIO server main function */
int main(int argc, char **argv)
{
int c;
char host[128] = "localhost";
char log_buf[LOGBUFSZ];
int port = 8080, backlog = 100;
enum SERVERTYPE servertype = COMMON;
int helpflg = 0,
errflg = 0,
debug = 0;
struct option longopts[] =
{
{"host", 1, 0, 'h'},
{"port", 1, 0, 'p'},
{"backlog", 1, 0, 'b'},
{"type", 1, 0, 't'},
{"keepalive", 0, 0, 'k'},
{"chunk", 0, 0, 'c'},
{"dime", 0, 0, 'd'},
{"debug", 0, 0, 'D'},
{"help", 0, &helpflg, 1},
{0, 0, 0, 0}
};
while ((c = getopt_long (argc, argv, "h:p:b:t:kcdD", longopts, NULL)) != EOF)
{
switch(c)
{
case 'h':
sprintf(host, "%s", optarg);
break;
case 'p':
port = atoi(optarg);
break;
case 'b':
backlog = atoi(optarg);
break;
case 't':
switch(*optarg)
{
case 'C':
servertype = COMMON;
break;
case 'S':
servertype = STANDALONE;
break;
case 'M':
servertype = MULTITHREAD;
break;
case 'P':
servertype = POOL;
break;
case 'Q':
servertype = QUEUE;
break;
case 'G':
servertype = GSI;
default:
break;
}
break;
case 'k':
keepalive = 1;
break;
case 'c':
chunk = 1;
break;
case 'd':
dime = 1;
break;
case 'D':
debug = 1;
break;
case '?':
errflg++;
break;
default:
break;
}
}
if(helpflg || errflg)
{
fprintf(stderr,"Usage: wsiod [OPTION]/n/n%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
"WSIO server based on web service./n",
"Mandatory arguments to long options are mandatory for short options too./n",
"/t-h, --host hostname in soap_bind, default is host which the service runs/n ",
"/t-p, --port port which the sercer runs on, default is 8080/n",
"/t-b, --backlog request backlog, default is 100/n",
"/t-t, --type server type, default is COMMON/n",
"/t-k, --keepalive attempt to keep socket connections alive/n",
"/t-c, --chunk use HTTP chunking/n",
"/t-d, --dime use DIME encoding/n",
"/t-D, --debug print debug info/n",
"/t --help print this help/n/n",
"Server type:/n",
"/tCOMMON the simplest server/n",
"/tSTANDALONE stand-alone server, which can run on port 80/n"
"/tMULTITHREAD multi-thread stand-alone server/n",
"/tPOOL using a pool of servers/n",
"/tQUEUE using a queue of requests for server/n",
"/tGSI prethreaded server with GSI enabled/n/n",
"Report bugs to <Aigui.LIU@ihep.ac.cn>./n"
);
exit(0);
}
/* 省略部分 */
return 0;
}
相关文章
- linux下使用vim编写运行C,C++程序(以hello world为例)
- Linux 系统下 C/C++ 程序编译
- C++main函数与命令行参数,退出程序
- linux不同环境下c/c++程序移植方法
- Linux下, Eclipse C/C++ IDE下编辑好C/C++源程序之后要先保存!!!否则,就会……
- Linux下的C程序如何调用系统命令,并获取系统的输出信息到C程序中
- RabbitMQ 优点和缺点- 消息可靠性:RabbitMQ 提供了持久化功能和消息确认机制,确保消息在各种情况下都能可靠地存储和处理。 灵活的路由:通过多种交换机类型和绑定规则,RabbitMQ 能够灵活地路由消息到指定的队列。 支持多种消息协议:实现了 AMQP 等(MQTT、STOMP)标准化、开放的消息队列协议,使其能够与多种语言编写的应用程序进行通信。 插件化扩展:RabbitMQ 提供了丰富的插件系统,可以通过插件扩展功能,如死信队列、压缩、追踪等。 高可用性:支持集群模式和镜像队列,确保服务的可用性 易用性和可管理性:提供了丰富的 API 和管理工具,以及多种客户端库和框架支持,易于集成和使用。 多语言支持:RabbitMQ 支持多种编程语言的客户端,包括 Java、Python、Ruby、C#、Node.js 等,方便开发人员集成到各种应用中。 高性能:在处理大量并发消息时表现出色。 广泛的社区支持:拥有庞大的开发者社区和丰富的文档资源。 劣势: 性能和吞吐量较低:相比于 Apache Kafka 等面向大数据流处理的消息队列系统,RabbitMQ 的吞吐量较低,不适合处理海量的实时数据流。RabbitMQ 的设计更注重消息的可靠性和灵活性,而非极高的吞吐性能。
- Linux C 程序 预处理,结构体(13)
- linux下c程序的链接、装载和库(1)
- 在CMD命令行模式下ADB命令显示为不是内部或外部命令,亦不是可运行程序和批处理文件的解决办法