當我們在輸入一個Linux Shell Script的指令時,例如ICMP (Internet Control Message Protocol,網路控制訊息協定)的ping指令時:
[root@localhost]# ping -I eth0 -c 4 www.google.com.tw -v以上這乙行的指令和後面的參數是代表什麼意思?
「-I」的'I'指的是Interface (介面);后面接了一個參數「eth0」─我要使用的是eth0這個網絡卡的介面;
「-c」的'c'指的是count (次數);後面也接了一個參數'4',表示要執行4次;
www.google.com.tw指的就是我要執行ping的網址;
最後的「-v」指的是view (檢視),我要把執行的結果給呈現出來。
類似這種在執行時需要帶參數的指令非常的多,所以C99有一個getopt()這樣的一個函式,來解決程式設計師們在設計軟體上時的問題。
還有另外一種指令的格式是像這個樣子的:
[root@localhost]# ps lx | grep "bash" --color「--color」指的就是我們要將grep出來的結果特別用顏色給標示出來。
像"--color"這種長選項,C99也提供了一個getopt_long()這樣的一個函式;但是─getopt_long()也可以向下相容於getopt()函式!
或許有人會覺得:我也可以善用主程式當中的int argc和char *argv[]來做處理呀!當然也是可以,只不過要在程式碼中做很多的防呆判斷機制,比較麻煩。
所以,就是這一篇文章的重點─我想要記錄一個getopt_long()函式的範例,爾後在工作上就可以直接地Copy-Paste了!先來看一下這個函式的基本介紹:
功能說明:分析命令列參數。
標頭檔:#include <getopt.h>
函式宣告:int getopt_long(int argc, const char *argv[], const char *optstring, const struct option *longopts, int *longindex);
函式說明:
1. int argc; argc就是執行程序時所帶的參數個數 (Argument Count)。例如指令:
./a.out; argc就為1;
./a.out -c -d; argc就為3;
./a.out -a -b 1234; argc就為4。
2. const char *argv[]; argv則是指執行程序時帶的參數變數 (Argument Variable)。例如指令:
./a.out; argv[0]為"./a.out";
./a.out -c -d; argv[0]為"./a.out",argv[1]為"-c",argv[2]為"-d";
./a.out -a -b 1234; argv[0]為"./a.out",argv[1]為"-a",argv[2]為"-b",argv[3]為"1234"。
3. const char *optstring; 代表欲處理的短選項字串。getopt_long()函式會回傳argv中下一個選項的字母。例如:"abc:d:"代表程序後面可以接上"-a", "-b", "-c"和"-d"等參數;'c'和'd'後面有冒號 (:)表這個短選項後面必須接參數值。所以,完整的指令應該像是這樣:
[root@localhost]# ./a.out -a -b -c 123456 -d "Hello!! World!! "4. const struct option *longopts; 引數longopts是一個結構指標,指向定義好、分析用的命令列參數資料。此一結構定義在:/usr/include/getopt.h (OS: Fedora Core 13)
結構內容如下:
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
a). const char *name; 命令列參數的長選項名稱;
b). int has_arg; 可有3個數值,其值與意義如下:
0: 參數後面沒有參數內容 (no_argument);
1: 參數後面必有參數內容 (required_argument);
2: 參數後面可有參數內容 (optional_argument)。
c). int *flag; 指向一個整數指標,如果此指標非NULL值,則會將函式傳回值存到指標指的位置。
d). int val; 函式的傳回值。
5. int *longindex; getopt_long()函式,在longopts結構陣列中,所尋找到的Index位置。
除此之外,getopt_long()函式還有用到一些全域變數 (Globle Variable):
6. extern char *optarg; 在getopt_long()函式之中的第3個引數const char *optstring,指的是所要搜尋的短選項;若短選項後面還有接上冒號 (:),則代表還必須接上一個參數值,而全域變數optarg就是指到這一個參數值。
7. extern int optind; 全域變數optind會指向在命令列當中第一個非'-'或是"--"開頭的參數。
範例:https://drive.google.com/open?id=1KxuBUXRs7_DLwxVKqZ4c71KY6uWD8X5Q
因為範例的程式碼有點大且複雜,所以我把它放在Google Driver上!
原本以為getopt_long()這個函式的範例應該還蠻簡單的,但沒想到卻足足花了我3、4天的時間在研究這個函式。getopt_long()就某種程度上而言,並沒想像中的那麼聰明,還是有一些地方必須靠程式設計師來自行判斷。例如,當我們在檢視程序 (Process)時的指令:
[root@localhost]# ps aux它等同於:
[root@localhost]# ps -a -u -x或者是當我們在安裝RPM (RedHat Package Management)管理套件時的指令:
[root@localhost]# rpm -ivh也等同於:
[root@localhost]# rpm -i -v -h以上兩種用法,getopt_long()函式都沒有幫我們判斷,要由程式設計師們自行另外增加判斷。所以,自己所撰寫的程式碼當中,也沒有以上兩種方式的判斷。
至於getopt_long()函式是如何測試的,測試時又發生了那些狀況?我想另外再寫兩篇測試的方法和心得。
(To be continue .... )
沒有留言:
張貼留言