Go語言 命令行解析(二)

今天我們繼續(xù)講解Go語言中命令行罐栈,當我們在解析命令行傳遞的參數(shù)時通常會想用最簡單的方法來解析自己行用到的命令行參數(shù)痕支,那么urfave/cli可以幫助我們快速的解析命令行參數(shù)雳攘,它是一個簡單快速的命令行包汛兜,用于在Go語言中構建命令行應用程序颠焦,目的是使開發(fā)人員能夠以表達的方式編寫快速分發(fā)的命令行應用程序,urfave/cli庫抽象出來:Flag里逆、Command,SubCommand等模塊进胯,用戶只需要設置模塊信息,參數(shù)的解析和關聯(lián)就可以原押,幫助信息自動生成胁镐。

在C語言中可以通過getopt(int argc, char * const argv[], const char *optstring)來完成參數(shù)解析,這里不做示例诸衔,有興趣的同學可以自己動手嘗試一下盯漂。

安裝urfave/cli:

go get github.com/urfave/cli

包引用方法:

import "github.com/urfave/cli" //引入cli包

urfave/cli包中幾個重要的方法:

cli.NewApp()    // 創(chuàng)建一個cli實例
Run()       // 程序入口,執(zhí)行Run后分析參數(shù)切片和路由
app.Commands    // 要執(zhí)行的命令列表
app.Before  // 運行命令之前執(zhí)行的內容
app.After   // 運行命令之后執(zhí)行的內容
Subcommands    // 子命令

好笨农,開始我們演示就缆,今天的演示示例有點長,項目目錄結構如下:

#tree
.
|-- commands
|   |-- api
|   |   `-- api.go        // api commands
|   `-- service
|       `-- service.go    // 服務 commands
|-- go_cli.go             // main入口
|-- go.mod                // go module管理包
|-- go.sum
`-- webservice
    |-- bin
    |   `-- webservice
    `-- webservice.go     // web服務類

首先谒亦,定義webservice類:

webservice類主要完成幾個功能:構造函數(shù)竭宰,釋放資源函數(shù),ApiService方法和Service方法份招。

package webservice

import "fmt"

// web service 類
type WebService struct {
    Config  string
    Port    int
    LogFile string
}

// 返回web service 實例
func NewWebService(config, logFile string, port int) *WebService {

    var ws = &WebService{
        Port:    port,
        Config:  config,
        LogFile: logFile,
    }
    return ws
}

// 釋放資源
func (ws *WebService) Freed() {

}

// API調用啟動方式
func (ws *WebService) ApiService() {
    fmt.Println("api service")
    fmt.Printf("port : %d \n", ws.Port)
    fmt.Printf("config : %s \n", ws.Config)
    fmt.Printf("logfile : %s \n", ws.LogFile)
    // 啟動http服務
}

// 常駐方式啟動
func (ws *WebService) Service() {
    fmt.Println("service")
    fmt.Printf("config : %s \n", ws.Config)
    fmt.Printf("logfile : %s \n", ws.LogFile)
    // 可以理解成類似Nginx這類服務的啟動
}

我們創(chuàng)建Api和Service兩個Commands的目錄切揭,用于分開執(zhí)行HTTPService和Service兩種模式。

ApiService:

在日常工作中脾还,HTTP-Api的試比較常見的獲取數(shù)據(jù)的方式伴箩,我們用這個例子來看看在命令行里面如何啟動和傳遞參數(shù)的。

package api

import (
    "fmt"
    "github.com/gzh/webservice"
    "github.com/urfave/cli"
    "os"
)

var Command = cli.Command{
    Name:    "api",
    Aliases: []string{"web_api", "webApi"}, // 命令別名
    Flags: []cli.Flag{
        // int型參數(shù)port鄙漏,value默認是8080
        cli.IntFlag{
            Name:  "port",
            Value: 8080,
            Usage: "/usr/local/web_service/service api --port=8080",
        },
        // 字符型參數(shù)配置文件嗤谚,默認值為空
        cli.StringFlag{
            Name:  "config",
            Value: "",
            Usage: "/usr/local/web_service/service api --config=/usr/local/web_service/config",
        },
        // 字符型日志文件參數(shù),默認值為空
        cli.StringFlag{
            Name:  "log_file",
            Value: "",
            Usage: "/usr/local/web_service/service api --log_file=/usr/local/web_service/log/web_service.log",
        },
    },
    Action: func(c *cli.Context) error {

        var port = c.Int("port")           // 從上下文中獲取端口
        var config = c.String("config")    // 從上下文中獲取配置文件
        var logFile = c.String("log_file") // 從上下文中獲取日志文件

        if config == "" {
            _, _ = fmt.Fprintf(os.Stderr, "config is empty!\n")
            os.Exit(100001) // 配置文件錯誤碼
        }

        if port <= 0 {
            _, _ = fmt.Fprintf(os.Stderr, "port is empty!\n")
            os.Exit(100002) // 端口錯誤碼
        }

        if logFile == "" {
            _, _ = fmt.Fprintf(os.Stderr, "log_file is empty!\n")
            os.Exit(100003) // 日志文件錯誤碼
        }

        // 實例webservice怔蚌,構造函數(shù)參數(shù):config巩步,logfile,port
        var api = webservice.NewWebService(config, logFile, port)
        defer api.Freed()

        // 啟動HTTP-API服務
        api.ApiService()

        return nil
    },
}

Service:

Service類似于Nginx一樣桦踊,啟動后常駐執(zhí)行的服務椅野,這種在后端中比較多見,下面的示例為Service的啟動和傳遞參數(shù)方式。

package service

import (
    "fmt"
    "github.com/gzh/webservice"
    "github.com/urfave/cli"
    "os"
)

var Command = cli.Command{
    Name: "service",
    Flags: []cli.Flag{
        // 字符型參數(shù)配置竟闪,默認值為空
        cli.StringFlag{
            Name:  "config",
            Value: "",
            Usage: "/usr/local/web_service/service api --config=/usr/local/web_service/config",
        },
        // 字符型日志文件參數(shù)离福,默認值為空
        cli.StringFlag{
            Name:  "log_file",
            Value: "",
            Usage: "/usr/local/web_service/service api --log_file=/usr/local/web_service/log/web_service.log",
        },
    },
    Action: func(c *cli.Context) error {

        var config = c.String("config")    // 從上下文中獲取配置文件
        var logFile = c.String("log_file") // 從上下文中獲取日志文件

        if config == "" {
            _, _ = fmt.Fprintf(os.Stderr, "config is empty!\n")
            os.Exit(100001) // 配置文件錯誤碼
        }

        if logFile == "" {
            _, _ = fmt.Fprintf(os.Stderr, "log_file is empty!\n")
            os.Exit(100003) // 日志文件錯誤碼
        }

        // 實例webservice,構造函數(shù)參數(shù):config炼蛤,logfile
        var api = webservice.NewWebService(config, logFile, 0)
        defer api.Freed()

        // 啟動服務
        api.Service()

        return nil
    },
}

完成上面的幾個類之后妖爷,我們可以創(chuàng)建go_cli.go文件開始我們的編碼。主要是實現(xiàn)main函數(shù)理朋,里面創(chuàng)建cli實例絮识,配置參數(shù)解析相關信息、版本嗽上、描述和幫助等信息次舌。

package main

import (
    "fmt"
    "github.com/gzh/commands/api"
    "github.com/gzh/commands/service"
    "github.com/urfave/cli"
    "os"
)

func main() {

    // 實例化命令行
    app := cli.NewApp()
    // 服務的名稱
    app.Name = "WebService"
    // 服務的描述
    app.Description = "Web服務相關描述"
    // 服務的用途描述
    app.Usage = "webservice api --port=8080 --config=path --log_file=/usr/local/webservice/log/go_cli.log"
    // 服務的版本號信息
    app.Version = "1.0.0"

    // 初始化多個命令
    app.Commands = []cli.Command{
        // api命令
        api.Command,
        // service命令
        service.Command,
    }
    app.Before = func(context *cli.Context) error {
        // 實現(xiàn)一些邏輯
        return nil
    }

    app.After = func(context *cli.Context) error {
        // 實現(xiàn)一些邏輯
        return nil
    }

    var err = app.Run(os.Args)
    if err != nil {
        fmt.Println("app run fatal! err : ", err)
    }
}

運行結果:

1、編譯運行Api示例:

#go build -o webservice/bin/webservice go_cli.go
#./webservice/bin/webservice api -port=8080 -config=path -log_file=/usr/local/webservice/log/go_cli.log
api service
port : 8080 
config : path 
logfile : /usr/local/webservice/log/go_cli.log 

2兽愤、編譯運行Service示例:

#go build -o webservice/bin/webservice go_cli.go
#./webservice/bin/webservice service -config=path -log_file=/usr/local/webservice/log/go_cli.log
service
config : path 
logfile : /usr/local/webservice/log/go_cli.log

3彼念、不傳遞任何參數(shù)的時候,會提示命令會出現(xiàn)HELP信息浅萧,運行如下国拇。

#go build -o webservice/bin/webservice go_cli.go
#./webservice/bin/webservice
NAME:
   WebService - webservice api --port=8080 --config=path --log_file=/usr/local/webservice/log/go_cli.log

USAGE:
   go_cli.exe [global options] command [command options] [arguments...]

VERSION:
   1.0.0

DESCRIPTION:
   Web服務相關描述

COMMANDS:
   api
   service
   help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version

總結:

命令行解析上支持的比較友好,支持的內容比較全面

使用上方便惯殊,快速

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市也殖,隨后出現(xiàn)的幾起案子土思,更是在濱河造成了極大的恐慌粪滤,老刑警劉巖崖蜜,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異巾腕,居然都是意外死亡捆毫,警方通過查閱死者的電腦和手機闪湾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绩卤,“玉大人途样,你說我怎么就攤上這事”舯铮” “怎么了何暇?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長凛驮。 經(jīng)常有香客問我裆站,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任宏胯,我火速辦了婚禮羽嫡,結果婚禮上,老公的妹妹穿的比我還像新娘肩袍。我一直安慰自己杭棵,他們只是感情好,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布了牛。 她就那樣靜靜地躺著颜屠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鹰祸。 梳的紋絲不亂的頭發(fā)上甫窟,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天,我揣著相機與錄音蛙婴,去河邊找鬼粗井。 笑死,一個胖子當著我的面吹牛街图,可吹牛的內容都是我干的浇衬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼餐济,長吁一口氣:“原來是場噩夢啊……” “哼耘擂!你這毒婦竟也來了?” 一聲冷哼從身側響起絮姆,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤醉冤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后篙悯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚁阳,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年鸽照,在試婚紗的時候發(fā)現(xiàn)自己被綠了螺捐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡矮燎,死狀恐怖定血,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情诞外,我是刑警寧澤糠悼,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站浅乔,受9級特大地震影響倔喂,放射性物質發(fā)生泄漏铝条。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一席噩、第九天 我趴在偏房一處隱蔽的房頂上張望班缰。 院中可真熱鬧,春花似錦悼枢、人聲如沸埠忘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽莹妒。三九已至,卻和暖如春绰上,著一層夾襖步出監(jiān)牢的瞬間旨怠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工蜈块, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鉴腻,地道東北人。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓百揭,卻偏偏與公主長得像爽哎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子器一,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內容