如何開發命令行程序

http://blog.csdn.net/luckheadline

一. 命令行規範

關於實現命令行參數, C 語言有着由來已久的傳統規範。

1. 可選命令行參數前有一個“ - ”, DOS WINDOWS 系統也可以用“ / ”。

2. 多個可選命令行參數之間沒有順序要求,每個參數都可以放置在參數列表中的任何位置。

3. 可選命令行參數本身可能會帶有參數。

4. 可能有些命令行程序並不遵從以上的規範,雖然這樣做並不推薦。

 

 

二. 如何實現命令行參數處理(以 C 語言爲例)

    命令行參數總是表現爲一個字符串數組,這個字符串數組被稱爲 ”argv”( 代表 arguments values), 還有一個整數 argc( 代表 arguments count) 用來表示命令行參數列表中參數的個數。因此,我們的 main 函數的格式如下:

        int main(int argc, char* argv[]), 務必要記住 argv[0] 是程序的名字,在 usage 聲明中你可能會用到它。 main 函數中的第一任務是實現可選參數,操作 argv 的標準方式如下所示:

 

 

  1. int  i;
  2. int  quiet=0;  //Value for the “-q” optional argument.
  3. for  (i = 1; i < argc; i ++)  //skip argv[0].
  4. {
  5. /*
  6.  *Use the ‘strcmp’ function to compare the argv values to a string
  7.  *of your choice(here, it’s a *optinal argument “-q”). When
  8.  *strcmp returns 0, it means that the two strings are identical.
  9. */
  10.      if  (strcmp(argv[i], “-q”) == 0)  //Process optional arguments
  11.     {
  12.         quiet = 1;  //This is used as a Boolean value.
  13.     }
  14.      else
  15.     {
  16.          //Process non-optional arguments here.
  17.     }
  18. }

請注意,正如這段代碼所示,可選參數“

-q ”可以被放置於參數列表的任何位置而且程序都可以正常 work 如果可選參數本身還有參數的話,那麼代碼將更加的 trickier

 

 

 

  1. int  i;
  2. int  opt = 0;
  3. int  optarg1 = 0;
  4. int  optarg2 = 0;
  5. for  (i = 1; i < argc; i ++)
  6. {
  7.      if  (strcmp(argv[i], “-opt”) == 0)
  8.     {
  9.         opt = 1;  //This is used as a boolean value.
  10.          /*
  11.          *The last argument is argv[argc -1]. Make sure there
  12.          *are enough arguments.
  13.         */
  14.          if  (i + 2 <= argc - 1)  //There are enough arguments in argv.
  15.         {
  16.              /*
  17.              *Increment ‘i’ twice so that you don’t check
  18.              *these arguments the next time through the loop.
  19.             */
  20.             i ++;
  21.             optarg1 = atoi(argv[i]);  //Convert string to int
  22.             i ++;
  23.             optarg2 = atoi(argv[i]);
  24.         }
  25.          else
  26.         {
  27.              //Print usage statement and exit.
  28.         }
  29.     }
  30.      else
  31.     {
  32.          //Process non-optional arguments here.
  33.     }
  34. }

    在很多情況下,命令行處理可能會非常麻煩,不過上面的代碼已經可以應付相當多的情況了。

 

 

BTW, Linux 下,習慣上會有兩種形式的命令行參數,一種是短形式,通常由 ”-” 加一個字母組成,這種形式的好處是便捷;另一種是長形式,通常由 ”--” 加一個單詞組成,這種形式的好處是形象,好記,直觀。

 

 

 

三. Usage 聲明

有時候,用戶可能會輸入不合法的命令行參數,你的程序需要處理這種情況以避免程序 crash 。這種情況的正確處理方式是:

1.   顯示 usage 聲明

2.   退出程序

例如,假設你的程序除了程序名還期望有 3 個參數,並且要接受另外一個可選參數:

usage 聲明的以下幾點意見:

 

 

 

1. usage 信息 : 總是使用“ usage ”開頭,接着是程序名和參數名。參數名應該儘可能的指明參數的意義,比如上面的 filename 。參數名不應該包含空格!可選參數使用 [] ,比如上面程序中的 ”-w” 。非可選參數不要使用 [] !總是打印 stderr ,而非 stdout ,以指明程序沒有正確 invoke

2. 程序名:總是使用 argv[0] 以指明程序名而非顯式的指出。因爲這樣,當你重新命名程序之後,不用重寫代碼。

3. 退出程序:使用 exit 函數( exit 函數被定義在頭文件 <stdlib.h> )。 exit 函數的任何非零參數都標誌着程序的非正常結束( exit 0 )標識程序的正常執行,但你很少會像這樣用)。你也可以使用宏 EXIT_FAILURE EXIT_SUCCESS 以取代 1 0 作爲 exit 函數的參數。

如果不得不多次寫 usage 聲明,你可以將它分離出來作爲一個獨立的函數,並且將程序名( argv[0] )作爲參數傳給它。那樣它就可以被 main 函數在任何需要的時候調用了。

 

四. 常見錯誤

1. 當程序接收到不正確參數時,應該總是打印一個 usage 消息給 stderr 。如果處理失敗將會自動 redo

2. 不要假設可選參數會固定放在參數列表的某個位置上。

3. 如果不方便的話,就不要嘗試一遍處理所有的命令行參數。

4. 不要修改 argv 數組。

 

五. getOpt() 的使用

getOpt() 是一個專門設計來減輕命令行處理負擔的庫函數。它位於 unistd.h 系統頭文件中,其原型如下:

int getopt(int argc, char *const argv[], const char *optstring);

函數給定了命令參數的數量 (argc) ,指向這些參數的數組 (argv) 和選項字符串 (optstring) 後, getopt() 將返回第一個選項,並設置一些全局變量。使用相同的參數再次調用該函數時,它將返回下一個選項,並設置相應的全局變量。如果不再有識別到的選項,將返回 -1 ,此任務就完成了。

getopt() 所設置的全局變量包括:

optarg :指向當前選項參數(如果有)的指針。

optind :再次調用 getopt() 時的下一個 argv 指針的索引。

optopt :最後一個已知選項。

可以重複調用 getopt() ,直到其返回 -1 爲止;任何剩下的命令行參數通常視爲文件名或稱程序相應的其他內容。見以下代碼示例:

 

 

 

Unix 程序還支持長選項,可以通過使用 getopt_long() 向程序添加長選項支持,因爲 getopt_long() 是同時支持長選項和短選項的 getopt() 版本。 getopt_long() 函數還接受其他參數,其中一個是指向 struct option 對象數組的指針。結構如下:

成員是指向長選項名稱(帶兩個短橫線)的指針。 has_arg 成員設置爲 no_argument, optional_argument, required_argument (均在 getopt.h 中定義)之一,以指示選項是否具有參數。如果 flag 成員未設置爲 NULL ,在處理期間遇到此選項時,會使用 val 成員的值填充它所指向的 int 值。如果 flag 成員爲 NULL ,在 getopt_long() 遇到此選項時,將返回 val 中的值;通過將 val 設置爲選項的 short 參數,可以在不添加任何其他代碼的情況下使用 getopt_long()—— 處理 while loop switch 的現有 getopt() 將自動處理此選項。代碼示例可以參見 reference 5

 

 

 

 

 

Reference:

http://www.cs.caltech.edu/courses/cs11/material/c/mike/misc/cmdline_args.html

http://www.ibm.com/developerworks/cn/linux/shell/clutil/index.html

http://linux.chinaitlab.com/command/4198.html

http://www.gnu.org/software/libtool/manual/libc/Getopt.html

http://www.ibm.com/developerworks/cn/aix/library/au-unix-getopt.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章