# 命令行编程

## 使用`os.Args`获取命令行参数

`os.Args`切片存储了命令行的所有参数，其中首位元素为命令名称：

```go
package main

import (
    "fmt"
    "os"
)

func main() {
    s, sep := "", ""
    for _, arg := range os.Args { // 通常使用方式：args := os.Args[1:]
        s += sep + arg
        sep = " "
    }
    fmt.Println(s)
}
```

构建完毕后，执行可执行程序main： `./main a bcd edf`结果如下

```
~/GlandProject/bin/main a bcd edf
```

## 使用`flag`获取命令行参数

```go
package main

import "flag"
import "fmt"

// 定义命令行参数对应的变量，这三个变量都是指针类型
// 参数1代表命令行参数名称
// 参数2代表命令行参数默认值
// 参数3代表输入help命令的提示
var cliName = flag.String("name", "nick", "Input Your Name")
var cliAge = flag.Int("age", 28, "Input Your Age")
var cliGender = flag.String("gender", "male", "Input Your Gender")

// 定义一个值类型的命令行参数变量，在 Init() 函数中对其初始化
// 因此，命令行参数对应变量的定义和初始化是可以分开的
var cliFlag int
func init() {
    flag.IntVar(&cliFlag, "flagname", 1234, "Just for demo")
}

func main() {
    // 把用户传递的命令行参数解析为对应变量的值
    flag.Parse()

    // flag.Args() 函数返回没有被解析的命令行参数
    // func NArg() 函数返回没有被解析的命令行参数的个数
    fmt.Printf("args=%s, num=%d\n", flag.Args(), flag.NArg())
    for i := 0; i != flag.NArg(); i++ {
        fmt.Printf("arg[%d]=%s\n", i, flag.Arg(i))
    }

    // 输出命令行参数
    fmt.Println("name=", *cliName)
    fmt.Println("age=", *cliAge)
    fmt.Println("gender=", *cliGender)
    fmt.Println("flagname=", cliFlag)
}
```

**无任何输入参数调用：**

```
$ ./main        
args=[], num=0
name= nick
age= 28
gender= male
flagname= 1234
```

**传递参数调用：**

```
$ ./main -name=zhangsan -age=18 -gender=人妖  
args=[], num=0
name= zhangsan
age= 18
gender= 人妖
flagname= 1234
```

**传递错误的参数：**

```
$ ./main -hobby=study             # 没有hobby参数            
flag provided but not defined: -hobby
Usage of ./main:
  -age int
        Input Your Age (default 28)
  -flagname int
        Just for demo (default 1234)
  -gender string
        Input Your Gender (default "male")
  -name string
        Input Your Name (default "nick")
```

**传递多余的参数调用：**

```
$ ./main -name=李四 a bc
args=[a bc], num=2 # 这是多余的参数，多余参数不能是 -xxx 或者 --xxx的形式
arg[0]=a
arg[1]=bc
name= 李四
age= 28
gender= male
flagname= 1234
```

### 查看帮助命令

`flag`会自动为程序生成帮助命令：

```
$ ./main --help       # 或者使用 -h
Usage of ./main:
  -age int
        Input Your Age (default 28)
  -flagname int
        Just for demo (default 1234)
  -gender string
        Input Your Gender (default "male")
  -name string
        Input Your Name (default "nick")
```

### 命令行传参形式

* 单个bool标志：`main -b=true`，可以省略为`main -b`
* 一下四种传参形式是相同的：
  * `main --name=zhangsa`
  * `main --name zhangsan`
  * `main -name=zhangsan`
  * `main -name zhangsan`
* 约定俗称将单个`-`表示命令参数的缩写，两个`-`，也就是`--`表示命令参数全写

### 非标志参数

也就是不带`-`的参数：

```go
flag.Args()
```

### 命令缩写实现

通过提供2个标志处理程序实现：

```go
var gopherType string

func init() {
    const (
        defaultGopher = "pocket"
        usage         = "the variety of gopher"
    )
    flag.StringVar(&gopherType, "gopher_type", defaultGopher, usage)
    flag.StringVar(&gopherType, "g", defaultGopher, usage+" (shorthand)")
}
```

### 强制参数

也就是必需参数，通过判断值是否为零值确认：

```go
// [...]
flag.Parse()

if *count == "" {
    flag.PrintDefaults()
    os.Exit(1) // 以代码1退出
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yangsx95.gitbook.io/notes/programming-language/golang/ming-ling-xing-bian-cheng.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
