Calvert's murmur

Go 的命令列旗標/選項

2021-09-16

約 3394 字 / 需 18 分鐘閱讀

原文:CalliCoderGo Command-line flags/options

命令列程式通常會接受來自使用者的旗標或選項來自訂指令的執行。旗標是在執行指令時加在指令名稱後的鍵值對。

Go 允許你使用標準函式庫中的 flags package 來接收命令列旗標。在本文中,你將學到如何為命令列程式接收旗標。

Go 的命令列旗標

要接收命令列旗標,你需要定義旗標以便從命令列取值。你可以透過多種方式做到:

  1. 使用 flag.String()flag.Bool()flag.Int() 等方法定義旗標。
  2. 使用 flag.StringVar(), flag.IntVar() 等方法將現有變數綁定到命令列旗標。
  3. 透過宣告一個實作 flag.Value 介面的類型來建立自訂旗標,然後使用 flag.Var() 方法將自訂類型的變數與命令列旗標綁定。

讓我們在以下範例中看看前兩種方法。我們會在其他範例看到第三種方法。

package main

import (
	"flag"
	"fmt"
	"strings"
)

func main() {
	// Declare a string flag called name with a default value ("Guest") and a help message
	name := flag.String("name", "Guest", "specify your name")

	// Declare a flag called age with default value of 0 and a help message
	age := flag.Int("age", 0, "specify your age")

	// Bind the command-line flag with an existing variable
	var country string
	flag.StringVar(&country, "country", "", "enter your country")

    // Enable command-line parsing
	flag.Parse()

	fmt.Printf("Hello %s\n", *name)
	fmt.Printf("Your age is %d\n", *age)
	fmt.Printf("Your are from %s\n", country)
}
# Build the program
$ go build command-line-flags.go

使用 -h 或 --help 旗標來取得命令列程式的輔助說明

$ ./command-line-flags -h
Usage of ./command-line-flags:
  -age int
    	specify your age
  -country string
    	enter your country
  -name string
    	specify your name (default "Guest")

使用空格分隔的鍵值對提供旗標

$ ./command-line-flags -name Rajeev -age 28 -country India
Hello Rajeev
Your age is 28
Your are from India

使用 鍵=值 的格式提供旗標

$ ./command-line-flags -name=Rajeev -age=28 -country="United Kingdom"
Hello Rajeev
Your age is 28
Your are from United Kingdom

如果未指定,則旗標使用預設值

$ ./command-line-flags -age=24 -country="United States"
Hello Guest
Your age is 24
Your are from United States

建立自訂命令列旗標

以下範例示範了如何建立自訂旗標。在這個範例中,我們定義並解析以逗號分隔的命令列旗標。

package main

import (
	"flag"
	"fmt"
	"strings"
)

// A custom type that implements the flag.Value interface
type hobbies []string

func (h *hobbies) String() string {
	return fmt.Sprint(*h)
}

func (h *hobbies) Set(value string) error {
	for _, hobby := range strings.Split(value, ",") {
		*h = append(*h, hobby)
	}
	return nil
}

func main() {
    // Define a custom flag
	var hobbiesFlag hobbies
	flag.Var(&hobbiesFlag, "hobbies", "comma separated list of hobbies")

    // Enable command-line parsing
	flag.Parse()

	fmt.Printf("Your hobbies are: ")
	for _, hobby := range hobbiesFlag {
		fmt.Printf("%s ", hobby)
	}
	fmt.Println()
}
# Output
$ ./command-line-flags -hobbies=Sports,Photography,Coding
Your hobbies are: Sports Photography Coding

使用旗標 package 處理位置引數

flag.Parse() 函數會持續解析它遇到的旗標,直到它偵測到非旗標引數(位置引數)。旗標 package 透過 Args()Arg() 函數讓你可以使用位置引數。

請注意,旗標 package 要求所有旗標都出現在位置引數之前。否則,旗標會被直譯為位置引數。

讓我們來看一個位置引數的範例。假設我們正在撰寫一個程式,用來在檔案中的起始行號到結束行號搜尋給定的關鍵字清單。在以下範例中,我們接受作為旗標的起始和結束行號,以及作為位置引數的關鍵字清單:

package main

import (
	"flag"
	"fmt"
)

func main() {
	s := flag.Int("s", 0, "start line number")
    t := flag.Int("t", 0, "end line number")

	// Enable command-line parsing
	flag.Parse()

	fmt.Printf("Search file from line number %d to %d\n", *s, *t)

    // Read all the positional arguments
	fmt.Println("for keywords:", flag.Args())

    // Read the i'th positional argument
	i := 0
	fmt.Printf("The keyword at index %d: %v\n", i, flag.Arg(i))
}

以下是向程式提供旗標和非旗標引數的方法:

$ go build command-line-flags.go

$ ./command-line-flags -s 1 -t 100 Go Java
Search file from line number 1 to 100
for keywords: [Go Java]
The keyword at index 0: Go

你必須在位置引數之前指定旗標。否則,旗標也會被直譯為位置引數:

$ ./command-line-flags Go Java -s 1 -t 100
Search file from line number 0 to 0
for keywords: [Go Java -s 1 -t 100]
The keyword at index 0: Go