cli库使用文档和实例-创建用户sql编写
cli库使用文档和实例
简介
cli是一个用于构建命令行程序的库。非常简洁,所有的初始化操作就是创建一个cli.App
结构的对象。通过为对象的字段赋值来添加相应的功能。
快速使用
cli
需要搭配 Go Modules 使用。创建目录并初始化:
$ mkdir cli && cd cli
$ go mod init github.com/darjun/go-daily-lib/cli
安装cli
库,有v1
和v2
两个版本。如果没有特殊需求,一般安装v2
版本:
$ go get -u github.com/urfave/cli/v2
使用:
package main
import (
"fmt"
"log"
"os"
"github.com/urfave/cli/v2"
)
func main() {
app := &cli.App{
Name: "hello",
Usage: "hello world example",
Action: func(c *cli.Context) error {
fmt.Println("hello world")
return nil
},
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
使用非常简单,理论上创建一个cli.App
结构的对象,然后调用其Run()
方法,传入命令行的参数即可。一个空白的cli
应用程序如下:
func main() {
(&cli.App{}).Run(os.Args)
}
但是这个空白程序没有什么用处。我们的hello world
程序,设置了Name/Usage/Action
。Name
和Usage
都显示在帮助中,Action
是调用该命令行程序时实际执行的函数,需要的信息可以从参数cli.Context
获取。
编译、运行(环境:Win10 + Git Bash):
$ go build -o hello
$ ./hello
hello world
除了这些,cli
为我们额外生成了帮助信息:
$ ./hello --help
NAME:
hello - hello world example
USAGE:
hello [global options] command [command options] [arguments...]
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help (default: false)
如果是需要看各种参数及具体选型使用,可移步:https://segmentfault.com/a/1190000023009961
接下来是一个小的实例: 使用cli分模块的配置各个小功能及实现:
先看下目录结构:
longyu@longyu:/xx/c/xxx/xx/GolandProjects/ADBTools$ tree -a
.
├── .idea #goland的目录 不用管
│ ├── .gitignore
│ ├── ADBTools.iml
│ ├── MarsCodeWorkspaceAppSettings.xml
│ ├── modules.xml
│ └── workspace.xml
├── ADBTools.exe #最终生成的运行工具
├── cmd #每一个具体的功能选型
│ ├── RunCreateUser.go
│ └── runRuokouling.go
├── go.mod
├── go.sum
├── main.go #主入口
├── rksOUTPUT #结果输出
│ ├── 创建用户SQL_2025-07-07.xlsx
│ └── 数据库弱口令筛查_2025-07.xlsx
└── utils #具体实现其功能的实际操作代码
├── CreateUserSQLAction.go
└── RuoKouLingAction.go
main.go
package main
import (
"ADBTools/cmd"
"github.com/urfave/cli/v2"
"log"
"os"
)
func main() {
app := &cli.App{
EnableBashCompletion: true,
Name: "ADBTools",
Usage: "用于使用便捷的小工具",
Description: `ADBTools 是一个多功能命令行工具集合,目前支持:
- 弱口令筛查
- 创建用户sql输出
后续将持续扩展更多实用功能。
`,
Version: "v0.0.1",
Commands: []*cli.Command{
cmd.RunRuokouling(),
cmd.RunCreateUser(),
},
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
这里配置了整体命令的主框架,简介一下这个工作的用作,功能,作者等,就是个简单的介绍.
Commands
处将写出具体实现的功能接口,如cmd.RunCreateUser()
即是创建用户sql输出的功能接口.
接下来就以cmd.RunCreateUser()
这个功能接口展示:
RunCreateUser.go
package cmd
import (
"ADBTools/utils"
"github.com/urfave/cli/v2"
)
func RunCreateUser() *cli.Command {
return &cli.Command{
Name: "CreateUserSQL",
Aliases: []string{"cus"},
Usage: "生成用户创建SQL",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "account",
Aliases: []string{"c"},
Usage: "账户信息(Excel_xxxx.xls)",
Required: true,
},
},
Action: utils.CreateUserSQLAction,
}
}
这里去配置 "生成用户创建SQL" 这个功能具体的介绍(Usage),和需要传参的具体配置(Flags),最后在Action中 编写具体是实现方案
CreateUserSQLAction.go
package utils
import (
"fmt"
"github.com/urfave/cli/v2"
"github.com/xuri/excelize/v2"
"log"
"os"
"strings"
"time"
)
// 清洗 header 函数
func cleanHeader(s string) string {
s = strings.TrimSpace(s)
return strings.Join(strings.Fields(s), " ")
}
func excelToMap(filePath string) ([]map[string]interface{}, []string, error) {
// 打开 Excel 文件
f, err := excelize.OpenFile(filePath)
if err != nil {
fmt.Println("打开文件失败:", err)
return nil, nil, err
}
// 获取第一个工作表名称
sheetName := f.GetSheetName(f.GetActiveSheetIndex())
// 获取所有行数据
rows, err := f.GetRows(sheetName)
if err != nil {
fmt.Println("读取行失败:", err)
return nil, nil, err
}
// 1️⃣ 获取并清洗表头
rawHeaders := rows[0]
headers := make([]string, len(rawHeaders))
for i, h := range rawHeaders {
headers[i] = cleanHeader(h)
}
var data []map[string]interface{}
// 遍历其余行
for i := 1; i < len(rows); i++ {
row := rows[i]
rowMap := make(map[string]interface{})
for j, header := range headers {
if j < len(row) {
rowMap[header] = row[j]
} else {
rowMap[header] = nil
}
}
data = append(data, rowMap)
}
return data, headers, nil
}
func CreateUserSQLAction(c *cli.Context) error {
//ctx := c.Context
userlistFile := c.String("account")
if userlistFile == "" {
log.Fatal("必须提供 --account 文件路径")
}
fmt.Println("任务开始,按 Ctrl+C 取消...")
usersList, _, err := excelToMap(userlistFile)
if err != nil {
log.Fatalf("无法读取用户表文件: %v", err)
}
var outputMap []RowData
var createSQL, grantSQL string
for index, user := range usersList {
fmt.Println("第", index+1, "行:", user)
if val, ok := user["数据库类型"].(string); ok {
fmt.Println("数据库类型:", val)
if strings.Contains(strings.ToLower(val), "oracle") || strings.Contains(strings.ToLower(val), "ora") {
fmt.Println("匹配到Oracle数据库")
// 匹配 Oracle, 编写oracle版的创建用户SQL
createSQL = "CREATE USER " + user["登录帐号"].(string) + " IDENTIFIED BY " + user["登录密码"].(string) + ";"
// 赋权sql, 连接,增删改查
grantSQL = "GRANT CONNECT, CREATE ANY TABLE, UPDATE ANY TABLE , DELETE ANY TABLE, SELECT ANY TABLE TO " + user["登录帐号"].(string) + ";"
} else if strings.Contains(strings.ToLower(val), "pg") || strings.Contains(strings.ToLower(val), "postgresql") || strings.Contains(strings.ToLower(val), "panwei") {
createSQL = "CREATE USER " + user["登录帐号"].(string) + " WITH PASSWORD '" + user["登录密码"].(string) + "';"
grantSQL = "GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA xxxxxx TO " + user["登录帐号"].(string) + ";"
} else {
fmt.Println("匹配到非oracle的数据库")
// 以mysql风格创建用户
createSQL = "CREATE USER '" + user["登录帐号"].(string) + "'@'%' IDENTIFIED BY '" + user["登录密码"].(string) + "';"
grantSQL = "GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO '" + user["登录帐号"].(string) + "'@'%';"
}
}
beizhustr := ""
if bz, ok := user["备注"].(string); !ok {
beizhustr = ""
} else {
beizhustr = bz
}
outputMap = append(outputMap, RowData{
ziyuanming: user["资源名"].(string),
user: user["登录帐号"].(string),
shili: user["数据库实例"].(string),
ip: user["数据库IP"].(string),
leixing: user["数据库类型"].(string),
beizhu: beizhustr,
createSQL: createSQL,
grantSQL: grantSQL,
})
}
fmt.Println("============================================================")
//打开新文件 把创建用户SQL写入一个新sheet里
newFile := excelize.NewFile()
newFile.NewSheet("创建用户SQL")
for index, rows := range outputMap {
fmt.Println("资源名:", rows.ziyuanming, "用户名:", rows.user, "数据库实例:", rows.shili, "数据库IP:", rows.ip, "数据库类型:", rows.leixing)
headers := []interface{}{"创建用户SQL", "赋权SQL", "资源名", "用户名", "数据库实例", "数据库IP", "数据库类型"}
for colNum, header := range headers {
cell, _ := excelize.CoordinatesToCellName(colNum+1, 1)
newFile.SetCellValue("创建用户SQL", cell, header)
}
rowIdx := index + 2
newFile.SetCellValue("创建用户SQL", "A"+fmt.Sprint(rowIdx), rows.createSQL)
newFile.SetCellValue("创建用户SQL", "B"+fmt.Sprint(rowIdx), rows.grantSQL)
newFile.SetCellValue("创建用户SQL", "C"+fmt.Sprint(rowIdx), rows.ziyuanming)
newFile.SetCellValue("创建用户SQL", "D"+fmt.Sprint(rowIdx), rows.user)
newFile.SetCellValue("创建用户SQL", "E"+fmt.Sprint(rowIdx), rows.shili)
newFile.SetCellValue("创建用户SQL", "F"+fmt.Sprint(rowIdx), rows.ip)
newFile.SetCellValue("创建用户SQL", "G"+fmt.Sprint(rowIdx), rows.leixing)
newFile.SetCellValue("创建用户SQL", "H"+fmt.Sprint(rowIdx), rows.beizhu)
}
//删除默认sheet
newFile.DeleteSheet("Sheet1")
outputDir := "rksOUTPUT"
if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
log.Fatalf("创建输出目录失败: %v", err)
}
loc, _ := time.LoadLocation("Asia/Shanghai")
currentTime := time.Now().In(loc).Format("2006-01-01")
outputFileName := fmt.Sprintf("%s/创建用户SQL_%s.xlsx", outputDir, currentTime)
if err := newFile.SaveAs(outputFileName); err != nil {
log.Fatalf("保存 Excel 文件失败: %v", err)
}
fmt.Printf("✅ %s 文件已成功生成!", outputFileName)
return nil
}
在以上方法中,就没有cli那么标准化的要求了,只需要从CreateUserSQLAction(c *cli.Context)
中 *cli.Context将上面传参接过来,通过userlistFile := c.String("account")
获得具体参数,即可开始正常的功能书写.
由代码得知,我们通过一系列方法将excel中标题进行清洗整理, 并按照具体的数据库类型输出具体的create user语句.
- 感谢你赐予我前进的力量