原文地址git
CLI或者“command line interface”是用户在命令行下交互的程序。因为经过将程序编译到一个静态文件中来减小依赖,一次Go特别适合开发CLI程序。若是你编写过安装时须要各类依赖的CLI程序你就知道这个是有多重要了。
在这篇博客中咱们将介绍使用Go开发CLI的基本知识。 github
大多数CLI程序都须要输入一些参数。Go 语言将这些参数以字符串slice处理。 golang
var Args []string
查找当前应用的名字。学习
package main import ( "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下,你能够用一下命令编译运行:ui
go build
./example1
输出的结果是:spa
Program Name: ./example1
为了肯定有多少参数传入,能够计算全部参数的长度减1(记住,第一个参数老是程序的名字)。或者能够直接从os.Args[1:]来判断他的长度。 命令行
package main import ( "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。 code
下面是一个很快速的遍历参数的例子。 blog
package main import ( "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 -local Argument 2 is u=admin Argument 3 is --help
目前为止咱们已经知道如何在一个程序中查找参数的基本的方法。在这个级别查询他们而且将他们赋值给咱们的程序是很麻烦的。全部就有了Flag包。 ip
package main import ( "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.
不少CLI程序同时包含有标识和没有标识的参数。flag.Args() 将会直接返回哪些没有标识的参数。
package main import ( "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()) }
port = 9000 other args: [foo=10 -bar]
flag只要找到一个不包含的flag就会当即中止查询。
Go是一个强语言类型,因此若是咱们传递一个string给一个int类型的flag,它将会提示咱们:
package main import ( "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) }
invalid value “foo” for flag -p: strconv.ParseInt: parsing “foo”: invalid syntax Usage of ./example6: -p=8000: specify port to use. defaults to 8000
flag不只会提示咱们输入错误,同时还会输出默认的使用方法。
flag包声明了一个Usage的方法。这样咱们就能够输出咱们想要输出的Usage了。
package main import ( "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() }
Usage of ./example7:
example7 file1 file2 …
目前为止咱们只是经过CLI输出了信息,可是不接受任何输入。咱们能够基本的fmt.Scanf()来捕捉输入。
package main import "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) } }
fmt.Scanf 对于简单的输入颇有效,可是有时候咱们可能须要一整行的数据。
package main import ( "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程序。
package main import ( "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
还有一些第三方库可让写CLI程序更简单: