Files
the-way-to-go_ZH_CN/eBook/12.4.md
Haigang Zhou d29644465a 第十二章修改 (#838)
Co-authored-by: Joe Chen <jc@unknwon.io>
2022-05-12 21:59:20 +08:00

135 lines
4.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)