
一 概述
二 現有的命令列解析方法
// demo.go
var limit int
flag.IntVar(&limit, "limit", 10, "the max number of results")
flag.Parse()
fmt.Println("the limit is", limit)
// 執行結果
$ go run demo.go
the limit is 10
$ go run demo.go -limit 100
the limit is 100
package main
import (
"fmt"
"strings"
"github.com/spf13/cobra"
)
funcmain() {
var echoTimes int
var cmdPrint = &cobra.Command{
Use: "print [string to print]",
Short: "Print anything to the screen",
Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Print: " + strings.Join(args, " "))
},
}
var cmdEcho = &cobra.Command{
Use: "echo [string to echo]",
Short: "Echo anything to the screen",
Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("Echo: " + strings.Join(args, " "))
},
}
var cmdTimes = &cobra.Command{
Use: "times [string to echo]",
Short: "Echo anything to the screen more times",
Long: `echo things multiple times back to the user by providing
a count and a string.`,
Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
for i := 0; i < echoTimes; i++ {
fmt.Println("Echo: " + strings.Join(args, " "))
}
},
}
cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
var rootCmd = &cobra.Command{Use: "app"}
rootCmd.AddCommand(cmdPrint, cmdEcho)
cmdEcho.AddCommand(cmdTimes)
rootCmd.Execute()
}
echotimes hello --times 3 go run cobra.go
Echo: hello
Echo: hello
Echo: hello
1 引數定義跟命令邏輯分離
// 為什麼我不能寫成下面這樣呢?
functimes(){
cobra.IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")
cobra.Parse()
}
2 子命令與父命令的順序定義不夠靈活
三 重新認識命令列
1 命令列只是一個可被 shell 解析執行的字串
cmd arg1 arg2 arg3
2 引數、標識與選項
flag.IntVar(&limit, "limit", 10, "the max number of results")
// 變數繫結,當在命令列中指定 -limit 100 的時候,這意味著我們是把 100 這個值,賦予變數 limit
3 子命令
// 不帶有橫線的引數也可以實現關聯變數或函式
for _, arg := range os.Args{
switch arg{
case"limit": // 設定 limit 變數
case"scan": // 呼叫 scan 函式
}
}
4 命令列的構成
-
標識(flag):以橫線或雙橫線開頭的引數,標識又由標識名和標識引數組成
-
–flagname flagarg
-
非標識引數
-
子命令(subcommand),子命令也會有子命令,標識和非標識引數
command --flag flagarg subcommand subcmdarg --subcmdfag subcmdflagarg
四 啟發式命令列解析
funccommand(){
// 定義 flags
// 呼叫 Parse 函式
}
echotimes hello --times 3 app
1 簡單解析流程
-
定義echo子命令關聯到函式echo, echo times子命令關聯到函式 echoTimes -
解析字串 echo times hello –times 3 -
解析第一個引數,透過 echo匹配到我們預定義的 echo子命令,同時發現這也是 echo times命令的字首部分,此時,只有知道後一個引數是什麼,我們才能確定使用者呼叫的是 echo還是 echo times -
解析第二個引數,透過 times我們匹配到 echo times子命令,並且其不再是任何子命令的字首。此時確定子命令為 echo times,其他所有引數皆為這個子命令的引數。 -
如果解析第二個引數為 hello,那麼其只能匹配到 echo這個子命令,那麼會呼叫 echo函式而不是 echoTimes函式。
2 啟發式探測流程
echo --color red times hello --times 3 app
-
解析到 red時,用 echo red搜尋預定義的子命令,若搜尋不到,則將 red視為引數 -
解析 times時,用 echo times搜尋預定義的子命令,此時可搜尋到 echo times子命令
3 子命令任意書寫順序
# 關聯到 echoTimes 函式
"echo times" => echoTimes
# 調整子命令只是改一下這個對映而已
"times echo" => echoTimes
五 Cortana: 基於啟發式命令列解析的實現
package main
import (
"fmt"
"strings"
"github.com/shafreeck/cortana"
)
funcprint() {
cortana.Title("Print anything to the screen")
cortana.Description(`print is for printing anything back to the screen.
For many years people have printed back to the screen.`)
args := struct {
Texts []string`cortana:"texts"`
}{}
cortana.Parse(&args)
fmt.Println(strings.Join(args.Texts, " "))
}
funcecho() {
cortana.Title("Echo anything to the screen")
cortana.Description(`echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`)
args := struct {
Texts []string`cortana:"texts"`
}{}
cortana.Parse(&args)
fmt.Println(strings.Join(args.Texts, " "))
}
funcechoTimes() {
cortana.Title("Echo anything to the screen more times")
cortana.Description(`echo things multiple times back to the user by providing
a count and a string.`)
args := struct {
Times int`cortana:"--times, -t, 1, times to echo the input"`
Texts []string`cortana:"texts"`
}{}
cortana.Parse(&args)
for i := 0; i < args.Times; i++ {
fmt.Println(strings.Join(args.Texts, " "))
}
}
funcmain() {
cortana.AddCommand("print", print, "print anything to the screen")
cortana.AddCommand("echo", echo, "echo anything to the screen")
cortana.AddCommand("echo times", echoTimes, "echo anything to the screen more times")
cortana.Launch()
}
# 不加任何子命令,輸出自動生成的幫助資訊
$ ./app
Available commands:
printprint anything to the screen
echoecho anything to the screen
echotimesecho anything to the screen more times
# 預設啟用 -h, --help 選項,開發者無需做任何事情
$ ./app print -h
Print anything to the screen
print is for printing anything back to the screen.
For many years people have printed back to the screen.
Usage: print [texts...]
-h, --helphelpfor the command
# echo 任意內容
$ ./app echo hello world
hello world
# echo 任意次數
$ ./app echotimes hello world --times 3
hello world
hello world
hello world
# --times 引數可以在任意位置
$ ./app echo --times 3 times hello world
hello world
hello world
hello world
1 選項與預設值
args := struct {
Times int`cortana:"--times, -t, 1, times to echo the input"`
Texts []string`cortana:"texts"`
}{}
-
長標識名(long): –flagname, 任意標識都支援長標識名的格式,如果不寫,則預設用欄位名
-
短標識名(short): -f,可以省略
-
預設值(default):可以為任意跟欄位型別匹配的值,如果省略,則預設為空值,如果為單個橫線 "-",則標識使用者必須提供一個值
-
描述(description):這個選項的描述資訊,用於生成幫助資訊,描述中可以包含任意可列印字元(包括逗號和空格)
2 子命令與別名
cortana.AddCommand("echo", echo, "echo anything to the screen")
// 定義 print 為 echo 命令的別名
cortana.Alias("print", "echo")
$ ./app print -h
Echo anything to the screen
echo is for echoing anything back.
Echo works a lot like print, except it has a child command.
Available commands:
echotimesecho anything to the screen more times
Usage: echo [texts...]
-h, --helphelpfor the command
cortana.Alias("three", "echo times --times 3")
echotimes --times 3 的別名 three 是
./app three hello world
hello world
hello world
hello world
3 help 標識和命令
cortana.Use(cortana.HelpFlag("--usage", "-u"))
# 自定義 --usage 來列印幫助資訊
$ ./app echo --usage
Echo anything to the screen
echo is for echoing anything back.
Echo works a lot like print, except it has a child command.
Available commands:
echotimesecho anything to the screen more times
Usage: echo [texts...]
-u, --usage helpfor the command
cortana.Alias("help", "--help")
// 透過別名,實現 help 命令,用於列印任意子命令的幫助資訊
$ ./app helpechotimes
Echo anything to the screen more times
echo things multiple times back to the user by providing
a count and a string.
Usage: echotimes [options] [texts...]
-t, --times <times> times to echo the input. (default=1)
-h, --helphelpfor the command
4 配置檔案與環境變數
預設值 < 配置檔案 < 環境變數 < 引數
cortana.AddConfig("app.json", cortana.UnmarshalFunc(json.Unmarshal))
5 沒有子命令?
funcmain(){
args := struct {
Version bool`cortana:"--version, -v, , print the command version"`
}{}
cortana.Parse(&args)
if args.Version {
fmt.Println("v0.1.1")
return
}
// ...
}
./app --version
v0.1.1
六 總結
專案地址:https://github.com/shafreeck/cortana
資料庫核心概念
資料庫,簡而言之可視為電子化的檔案櫃——儲存電子檔案的處所,使用者可以對檔案中的資料執行新增、擷取、更新、刪除等操作。資料庫管理系統(Database Management System,簡稱DBMS)是為管理資料庫而設計的電腦軟體系統,一般具有儲存、擷取、安全保障、備份等基礎功能 要想學習資料庫,需要了解SQL、索引、檢視、鎖等概念,本節課帶你走進資料庫。
關鍵詞
變數
字串
命令列
程式
語言