2012年10月29日 星期一

autoEM project: 系列二:option parser

最近因為寫autoEM用到的了python optparse函數,就把相關用法整理了一下。
另外之前看一個BASH譔寫的圖形處理程式(接近700行的code就能完成許多驚人的功能,真的有一點點誇張),也發現到原來BASH內就有內建getopts的功能,雖然說查了manpage發現: All parsing is done by the GNU getopt(3) routines,根本就是直接用C的getopt來做的嘛…
不過getopt在寫大型程式時常用到,就整理一下 C、BASH跟python optparse函數,讓自己不要忘掉,也給大家作個參考:

1. C:
在c裡面用的是unistd.h的getopt,這個方式不接受--XD之類的寫法,getopt_long有提供相關功能,用法還滿相似的,就給大家自己去研究:
getopt(argc, argv, optstring) 並有四個外部變數
extern char* optarg
extern int optind, opterr, optopt optstring
為指定getopt要辨識的參數,大略上有3條規則:
1. 在其中的character,都是合法的參數選項。
2. 後面有“:”的character,需要有後面附加的參數,如-f filename,getopt會將optarg指向該串文字。
3. 加上”::”的character,可以用直接連接的方式加上長參數,如 -oargument,此時optarg會指向argument,但使用者忘記寫argument的話,optarg會指向空字串。
getopt每parse一個參數,就會回傳parse到的參數到opt,如果掃完了,就會回傳-1;遇到不合法的參數,會回傳?;加上:的參數卻沒有在之後寫上對應的參數,則回傳?,如果在optstring第一個字元是:,則上述無參數的狀況會回傳:。

看不懂對不對,看一下怎麼用就明白了:
while((opt=getopt(argc,argv,":o::e:"))!=-1){
  switch(opt){
    case'o':
    printf("%s\n",optarg);
    break;
  case'e':
    printf("%s\n",optarg);
    break;
  case':':
    printf("didn't specify the argument\n");
    break;
  case'?':
    printf("unknown argument\n");
    break;
 }
}
上面只是在範例,把選項輸出一下,實際上要做什麼就做什麼,那其實BASH的情況下是幾乎一樣的寫法:
while getopts o:e: OPTION
do
  case $OPTION in
    o)
      …
    e)
      …
    ?)
      …
  esac
done

2. python的部分:
python下有兩個可行的方法 optparse或argparse,不過optparse好像不再支援,以aptparse為主體。
因為我2.7用的還是optparse,之後有空再來整理aptparse,應該不會差太多…吧?
1. 首先是引入optparse:
from optparse import OptionParser make_option
parser = OptionParser(usage = 'Usage: autoEM [OPTION...] PAGE...',
 option_list=option_list)
usage的部分會自動出現在./program -h時的第一行,同時python會自動將現在的option 2. 定義options: 有兩種方法定義options,一種是呼叫parser
parser.add_option('-v', '--version', action='store_true', dest='version', default=False, help='show version information')
另一種個人比較喜歡,先用make_option把選項都寫在一個set option_list 裡
option_list = [ 
    make_option('-v', '--version', action='store_true', dest='version', default=False, help='show version information') ] 
然後如上面paser = OptionParser的地方,用option_list=option_list把選項一口氣寫進去。

上面這個option,會接下的選項為:
-v foo
-vfoo
--version foo
--version=foo store
會設定options.X的值,X依序為dest ->長參數(version) → 短參數(v)如果前一個沒有給定的話,例如上面會設定options.version。
後面的參數可以加上type=int, float,不設的話store會以string的方式儲存。
另外有store_true, store_false,此時會將dest設為true或false。

3. 處理options:
呼叫parser_args處理argument,default會使用sys.argv[1:]作為參數,當然我們傳自己設定的argument。
options, args = parser.parse_args() args會儲存parse到多少個options。
接著就可以透過options.X的方式,一一寫下各自的處理方式,例如:
if options.filename:
 filename=options.filename
一般來說如果使用者忘了傳入特定參數,如-f忘了寫檔名,optparse都會自動輸出上面的usage,跟相關的錯誤訊息。如果我們要自行呼叫error,可以用parser.error()呼叫,如:
if options.a and options.b:
    parser.error('-a and -b can exist together')
另外optparse還有不少功能,不過上面的對於一般程式來說應該相當夠用了,剩下的就請大家自己去研究了。

3. 參考資料:
1. C的部分:
Linux manpage:
man 1 getopt for BASH
man 3 getopt for C
beginning linux programming 4/e
2.Python部分:
http://docs.python.org/library/optparse.html

沒有留言:

張貼留言