• 12.4 从命令行读取参数
    • 12.4.1 os 包
    • 12.4.2 flag 包

    12.4 从命令行读取参数

    12.4.1 os 包

    os 包中有一个 string 类型的切片变量 os.Args,用来处理一些基本的命令行参数,它在程序启动后读取命令行输入的参数。来看下面的打招呼程序:

    示例 12.11 os_args.go:

    1. // os_args.go
    2. package main
    3. import (
    4. "fmt"
    5. "os"
    6. "strings"
    7. )
    8. func main() {
    9. who := "Alice "
    10. if len(os.Args) > 1 {
    11. who += strings.Join(os.Args[1:], " ")
    12. }
    13. fmt.Println("Good Morning", who)
    14. }

    我们在 IDE 或编辑器中直接运行这个程序输出:Good Morning Alice

    我们在命令行运行 os_args or ./os_args 会得到同样的结果。

    但是我们在命令行加入参数,像这样:os_args John Bill Marc Luke,将得到这样的输出:Good Morning Alice John Bill Marc Luke

    这个命令行参数会放置在切片 os.Args[] 中(以空格分隔),从索引1开始(os.Args[0] 放的是程序本身的名字,在本例中是 os_args)。函数 strings.Join 以空格为间隔连接这些参数。

    练习 12.5:hello_who.go

    写一个”Hello World”的变种程序:把人的名字作为程序命令行执行的一个参数,比如: hello_who Evan Michael Laura 那么会输出Hello Evan Michael Laura!

    12.4.2 flag 包

    flag 包有一个扩展功能用来解析命令行选项。但是通常被用来替换基本常量,例如,在某些情况下我们希望在命令行给常量一些不一样的值。(参看 19 章的项目)

    在 flag 包中一个 Flag 被定义成一个含有如下字段的结构体:

    1. type Flag struct {
    2. Name string // name as it appears on command line
    3. Usage string // help message
    4. Value Value // value as set
    5. DefValue string // default value (as text); for usage message
    6. }

    下面的程序 echo.go 模拟了 Unix 的 echo 功能:

    1. package main
    2. import (
    3. "flag" // command line option parser
    4. "os"
    5. )
    6. var NewLine = flag.Bool("n", false, "print newline") // echo -n flag, of type *bool
    7. const (
    8. Space = " "
    9. Newline = "\n"
    10. )
    11. func main() {
    12. flag.PrintDefaults()
    13. flag.Parse() // Scans the arg list and sets up flags
    14. var s string = ""
    15. for i := 0; i < flag.NArg(); i++ {
    16. if i > 0 {
    17. s += " "
    18. if *NewLine { // -n is parsed, flag becomes true
    19. s += Newline
    20. }
    21. }
    22. s += flag.Arg(i)
    23. }
    24. os.Stdout.WriteString(s)
    25. }

    flag.Parse() 扫描参数列表(或者常量列表)并设置 flag, flag.Arg(i) 表示第i个参数。Parse() 之后 flag.Arg(i) 全部可用,flag.Arg(0) 就是第一个真实的 flag,而不是像 os.Args(0) 放置程序的名字。

    flag.Narg() 返回参数的数量。解析后 flag 或常量就可用了。
    flag.Bool() 定义了一个默认值是 false 的 flag:当在命令行出现了第一个参数(这里是 “n”),flag 被设置成 true(NewLine 是 *bool 类型)。flag 被解引用到 *NewLine,所以当值是 true 时将添加一个 newline(”\n”)。

    flag.PrintDefaults() 打印 flag 的使用帮助信息,本例中打印的是:

    1. -n=false: print newline

    flag.VisitAll(fn func(*Flag)) 是另一个有用的功能:按照字典顺序遍历 flag,并且对每个标签调用 fn (参考 15.8 章的例子)

    当在命令行(Windows)中执行:echo.exe A B C,将输出:A B C;执行 echo.exe -n A B C,将输出:

    1. A
    2. B
    3. C

    每个字符的输出都新起一行,每次都在输出的数据前面打印使用帮助信息:-n=false: print newline

    对于 flag.Bool 你可以设置布尔型 flag 来测试你的代码,例如定义一个 flag processedFlag:

    1. var processedFlag = flag.Bool(“proc”, false, nothing processed yet”)

    在后面用如下代码来测试:

    1. if *processedFlag { // found flag -proc
    2. r = process()
    3. }

    要给 flag 定义其它类型,可以使用 flag.Int()flag.Float64flag.String()

    在第 15.8 章你将找到一个具体的例子。