1. 程式人生 > >Golang: 使用flag包進行命令列引數解析

Golang: 使用flag包進行命令列引數解析

最近在使用go開發cli(command-line-interface)時,通過對於官方文件以及他人部落格的學習,在此寫下個人認為更適合自己往後回顧的關於flag的使用說明。

工欲善其事必先利其器,先奉上flag官方文件解析

Demo0:

package main
import (
    "fmt"
    "flag"
)
func main() {
    t1 := flag.Int("w",0,"demo test")
    t2 := flag.String("a","Hello","demo test")
    flag.Parse()
    fmt.Println
("t1 is ", *t1) fmt.Println("t2 is ", *t2) fmt.Printf("There is %d non-flag\n", flag.NArg()) for i,arg := range flag.Args() { fmt.Printf("%d is %s\n",i+1, arg) } }

從main往下看:第一句代表我們需要一個w的命令列引數,這個引數接收int型別的值。第二句同理,只是int換成了string。緊跟後面的0是我們設定的預設值,demo test則是我們給這個引數作用的說明,可以通過呼叫 flag.Usage() 看到。flag.Parse()代表我們開始解析引數,在Parse以後,我們是不允許再新增引數的,也就是說,我們不能寫了Parse之後再寫一個flag.Int()

。flag.NArg()用來輸出non-flag引數的個數。在講non-flag前,我們先看命令列標籤格式:

-flag
-flag=x
-flag x  // 只有非boolean標籤能這麼用
// 減號可以使用一個或者兩個,效果是一樣的。

一般而言,我們定義了的引數便是flag引數,使用的形式便是上述形式。而我們沒有定義的,又沒有使用上述格式的,我們一般便稱其為non-flag引數。可能有人有疑問,以Demo0程式碼為例,那 -p 應該算作什麼?這裡要分兩種情況:
go run demo0.go -w 10 -a hahaha -p start
此時的-p便為已使用但是未定義的flag引數
go run demo0.go -w 10 -a hahaha start -p 666


此時的-p便是non-flag引數。此時的重點就是,flag引數的解析在碰到第一個non-flag引數便會停止,即從第一個non-flag開始,後面出現的所有引數都將被認為是non-flag,不論你是否符合要求的命令列標籤格式。所以,以上述命令為例,non-flag引數有三個 : start 、 -p、666,所以如果你希望在non-flag後面仍然能像在non-flag之前一般處理(比如把666賦給p),可能需要做更多額外的處理工作才能完成。

Demo1:

package main

import (
    "fmt"
    "flag"
)
func main() {
    var t1 int
    flag.IntVar(&t1, "t", 0, "sample 1")
    t2 := flag.Int("t", 0, "sample 2")
    flag.Parse()
}

上述Demo目的在於講明flag.xxxVar 與 flag.xxx 間的區別。通過官方文件可以獲悉,flag.xxxVar需要你傳入一個指標作為引數,而flag.xxx則是返回一個指標值。具體應用場景大家見仁見智。於我個人而言,如果所需引數的作用是全域性的,我會選擇使用flag.xxxVar繫結到一個全域性變數之上,如果只是區域性作用,比如作為後續行為的一個選擇條件之一,那麼一般我會採用flag.xxx的形式

Demo2 :

package main

import (
    "fmt"
    "flag"
    "os"
)
func main() {
    var t1 int
    flag.IntVar(&t1, "t", 0, "1")
    t2 := flag.Int("t", 0, "2")
    flag.Parse()
    // 如果你希望使用自己寫的usage
    // flag.Usage = usage
    if t1 != 1 {
        flag.Usage()
    }
}
func usage() {
    fmt.Fprintf(os.Stderr, "That's good")
}

這裡主要講解flag.Usage()的使用,實際上這個函式便是將我們定義引數時寫的關於引數的說明進行輸出。一般而言,此函式一般在使用者使用錯誤時作為提示給出。根據文件,flag.Usage() 預設 輸出到 os.Stderr。我們也可以將之用自己的函式替代,從而打造更加個性化的提示。

End

實際上結合上述Demo已經能夠簡單的利用flag進行引數解析,如果希望追求更為複雜使用的使用方式,不建議使用flag包,不妨看看pflag或者goptions,相信你能有更加棒的收穫。