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;
}
本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/liuben/archive/2008/04/05/2252929.aspx