menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right All_wiki chevron_right the-way-to-go_ZH_CN chevron_right eBook chevron_right 12.4.md
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    12.4.md
    4.27 KB / 2024-07-16 23:14:28
        # 12.4 从命令行读取参数
    
    ## 12.4.1 os 包
    
    `os` 包中有一个 `string` 类型的切片变量 `os.Args`,用来处理一些基本的命令行参数,它在程序启动后读取命令行输入的参数。来看下面的打招呼程序:
    
    示例 12.11 [os_args.go](examples/chapter_12/os_args.go):
    
    ```go
    // os_args.go
    package main
    
    import (
    	"fmt"
    	"os"
    	"strings"
    )
    
    func main() {
    	who := "Alice "
    	if len(os.Args) > 1 {
    		who += strings.Join(os.Args[1:], " ")
    	}
    	fmt.Println("Good Morning", who)
    }
    ```
    
    我们在 IDE 或编辑器中直接运行这个程序输出:`Good Morning Alice`
    
    我们在命令行运行 `os_args` 或 `./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](exercises/chapter_12/hello_who.go)
    
    写一个“Hello World”的变种程序:把人的名字作为程序命令行执行的一个参数,比如: `hello_who Evan Michael Laura` 那么会输出 `Hello Evan Michael Laura!`
    
    ## 12.4.2 flag 包
    
    `flag` 包有一个扩展功能用来解析命令行选项。但是通常被用来替换基本常量,例如,在某些情况下我们希望在命令行给常量一些不一样的值。(参看 [19 章](19.0.md)的项目)
    
    在 `flag` 包中有一个 `Flag` 是被定义成一个含有如下字段的结构体:
    
    ```go
    type Flag struct {
    	Name     string // name as it appears on command line
    	Usage    string // help message
    	Value    Value  // value as set
    	DefValue string // default value (as text); for usage message
    }
    ```
    
    下面的程序 [echo.go](examples/chapter_12/echo.go) 模拟了 Unix 的 echo 功能:
    
    ```go
    package main
    
    import (
    	"flag" // command line option parser
    	"os"
    )
    
    var NewLine = flag.Bool("n", false, "print newline") // echo -n flag, of type *bool
    
    const (
    	Space   = " "
    	Newline = "\n"
    )
    
    func main() {
    	flag.PrintDefaults()
    	flag.Parse() // Scans the arg list and sets up flags
    	var s string = ""
    	for i := 0; i < flag.NArg(); i++ {
    		if i > 0 {
    			s += " "
    			if *NewLine { // -n is parsed, flag becomes true
    				s += Newline
    			}
    		}
    		s += flag.Arg(i)
    	}
    	os.Stdout.WriteString(s)
    }
    ```
    
    `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 的使用帮助信息,本例中打印的是:
    
    ```go
    -n=false: print newline
    ```
    
    `flag.VisitAll(fn func(*Flag))` 是另一个有用的功能:按照字典顺序遍历 flag,并且对每个标签调用 fn (参考 [15.8 章](15.8.md)的例子)
    
    当在命令行 (Windows) 中执行:`echo.exe A B C`,将输出:`A B C`;执行 `echo.exe -n A B C`,将输出:
    
    ```
    A
    B
    C
    ```
    
    每个字符的输出都新起一行,每次都在输出的数据前面打印使用帮助信息:`-n=false: print newline`。
    
    对于 `flag.Bool` 你可以设置布尔型 flag 来测试你的代码,例如定义一个 flag `processedFlag`:
    
    ```go
    var processedFlag = flag.Bool("proc", false, "nothing processed yet")
    ```
    
    在后面用如下代码来测试:
    
    ```go
    if *processedFlag { // found flag -proc
    	r = process()
    }
    ```
    
    要给 flag 定义其它类型,可以使用 `flag.Int()`,`flag.Float64()`,`flag.String()`。
    
    在[第 15.8 章](15.8.md)你将找到一个具体的例子。
    
    ## 链接
    
    - [目录](directory.md)
    - 上一节:[文件拷贝](12.3.md)
    - 下一节:[用 buffer 读取文件](12.5.md)
    
    
    links
    file_download