CLI:使用Go開發命令列應用

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
 

原文地址

CLI或者“command line interface”是使用者在命令列下互動的程式。由於通過將程式編譯到一個靜態檔案中來減少依賴,一次Go特別適合開發CLI程式。如果你編寫過安裝時需要各種依賴的CLI程式你就知道這個是有多重要了。
   在這篇部落格中我們將介紹使用Go開發CLI的基本知識。

Arguments

   大多數CLI程式都需要輸入一些參數。Go 語言將這些參數以字串slice處理。

var Args []string

尋找當前應用的名字。

package mainimport (    "fmt"    "os")func main() {    // Program Name is always the first (implicit) argument    cmd := os.Args[0]    fmt.Printf("Program Name: %s\n", cmd)}

這個應用再code/example1下,你可以用一下命令編譯運行:

go build./example1

輸出的結果是:

Program Name: ./example1
判斷傳入程式的參數數量

   為了確定有多少參數傳入,可以計算所有參數的長度減1(記住,第一個參數總是程式的名字)。或者可以直接從os.Args[1:]來判斷他的長度。

package mainimport (    "fmt"    "os")func main() {    argCount := len(os.Args[1:])    fmt.Printf("Total Arguments (excluding program name): %d\n", argCount)}

運行./example2 得到的結果將是0。運行./example2 -foo=bar 得到的記過將是1。

遍曆參數

   下面是一個很快速的遍曆參數的例子。

package mainimport (    "fmt"    "os")func main() {    for i, a := range os.Args[1:] {        fmt.Printf("Argument %d is %s\n", i+1, a)    }}Running the program with ./example3 -local u=admin --help results in:Argument 1 is -localArgument 2 is u=adminArgument 3 is --help
Flag 包

   目前為止我們已經知道如何在一個程式中尋找參數的基本的方法。在這個層級查詢他們並且將他們賦值給我們的程式是很麻煩的。所有就有了Flag包。

package mainimport (    "flag"    "fmt")func main() {    var port int    flag.IntVar(&port, "p", 8000, "specify port to use.  defaults to 8000.")    flag.Parse()    fmt.Printf("port = %d", port)}

我們首先做的是設定一個int類型的預設值是8000,並且有文字提示的標識。
   為了讓flag包對設定的變數賦值,需要是用flag.Parse()方法。
   不加參數的運行這個程式得到的結果是port = 8000,因為我們明確的指定了如果沒有參數傳遞給port,那麼就採用預設的8000.
   運行./example4 -p=9000 結果是 port = 9000
   同事flag提供了 “program useage”的輸出。如果我們運行 ./example4 -help 我們會得到:

Usage of ./example4:-p=8000: specify port to use.  defaults to 8000.
flag.Args()

   很多CLI程式同時包含有標識和沒有標識的參數。flag.Args() 將會直接返回哪些沒有標識的參數。

package mainimport (    "flag"    "fmt")func main() {    var port int    flag.IntVar(&port, "p", 8000, "specify port to use.  defaults to 8000.")    flag.Parse()    fmt.Printf("port = %d\n", port)    fmt.Printf("other args: %+v\n", flag.Args())}
運行./example5 -p=9000 foo=10 -bar 將會得到:
port = 9000other args: [foo=10 -bar]

flag只要找到一個不包含的flag就會立即停止查詢。

無效的flag參數

   Go是一個強語言類型,所以如果我們傳遞一個string給一個int類型的flag,它將會提示我們:

package mainimport (    "flag"    "fmt")func main() {    var port int    flag.IntVar(&port, "p", 8000, "specify port to use.  defaults to 8000")    flag.Parse()    fmt.Printf("port = %d", port)}
運行程式./example6 -p=foo 得到的結果是:
invalid value “foo” for flag -p: strconv.ParseInt: parsing “foo”: invalid syntaxUsage of ./example6:-p=8000: specify port to use.  defaults to 8000

flag不僅會提示我們輸入錯誤,同時還會輸出預設的使用方法。

flag.Usage

   flag包聲明了一個Usage的方法。這樣我們就可以輸出我們想要輸出的Usage了。

package mainimport (    "flag"    "fmt"    "os")func main() {    flag.Usage = func() {        fmt.Printf("Usage of %s:\n", os.Args[0])        fmt.Printf("    example7 file1 file2 ...\n")        flag.PrintDefaults()    }    flag.Parse()}
運行./example7 –help 得到的結果是:
Usage of ./example7:example7 file1 file2 …
擷取輸入

   目前為止我們只是通過CLI輸出了資訊,但是不接受任何輸入。我們可以基本的fmt.Scanf()來捕捉輸入。

package mainimport "fmt"func main() {    var guessColor string    const favColor = "blue"    for {        fmt.Println("Guess my favorite color:")        if _, err := fmt.Scanf("%s", &guessColor); err != nil {            fmt.Printf("%s\n", err)            return        }        if favColor == guessColor {            fmt.Printf("%q is my favorite color!", favColor)            return        }        fmt.Printf("Sorry, %q is not my favorite color.  Guess again.\n", guessColor)    }}
bufio.Scanner

   fmt.Scanf 對於簡單的輸入很有效,但是有時候我們可能需要一整行的資料。

package mainimport (    "bufio"    "fmt"    "os")func main() {    scanner := bufio.NewScanner(os.Stdin)    for scanner.Scan() {        line := scanner.Text()        if line == "exit" {            os.Exit(0)        }        fmt.Println(line) // Println will add back the final '\n'    }    if err := scanner.Err(); err != nil {        fmt.Fprintln(os.Stderr, "reading standard input:", err)    }}

這是一個基本的echo程式,如果要退出直接輸入exit即可。

一個基本的cat程式

   你應該用過很多次cat程式了。我們將會把這篇部落格學到的只是融合在一起構建一個基本的cat程式。

package mainimport (    "flag"    "fmt"    "io"    "os")func main() {    flag.Usage = func() {        fmt.Printf("Usage of %s:\n", os.Args[0])        fmt.Printf("    cat file1 file2 ...\n")        flag.PrintDefaults()    }    flag.Parse()    if flag.NArg() == 0 {        flag.Usage()        os.Exit(1)    }    for _, fn := range flag.Args() {        f, err := os.Open(fn);         if err != nil {            panic(err)        }        _, err = io.Copy(os.Stdout, f)        if err != nil {            panic(err)        }    }}
協助

   對於協助我們在上面已經講了,但是還沒有明確的定義
-h
–help

   上面這些都會觸發help。

總結

  本篇部落格中只是講了一些CLI的基本用法。如果想要學習更多,可以查看這些包的godoc

  • flag
  • bufio
  • fmt
其他的命令列庫

   還有一些第三方庫可以讓寫CLI程式更簡單:

  • comandante
  • viper

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.