下面由golang教程栏目给大家介绍一个golang常见库cobra,希望对需要的朋友有所帮助!
cobra 是 go 语言的一个库,可以用于编写命令行工具。通常我们可以看到git pull
、docker container start
、apt install
等等这样命令,都可以很容易用corba来实现,另外,go 语言是很容易编译成一个二进制文件,本文将实现一个简单的命令行工具。
具体写一个例子, 设计一个命令叫blog
, 有四个子命令
1 2 3 4 | blog new [post-name] :创建一篇新的blog
blog list :列出当前有哪些文章
blog delete [post-name]: 删除某一篇文章
blog edit [post-name]:编辑某一篇文章
|
登录后复制
计划有以下几个步骤
- 创建模块
- 用cobra的命令行,创建命令行入口
- 用cobra的命令行,创建子命令
- 编写功能逻辑
创建模块
1 2 | $ go mod init github.com/shalk/blog
go: creating new go.mod: module github.com/shalk/blog
|
登录后复制
创建命令行入口
说到命令行,可能会想到bash的getopt 或者 java 的jcommand,可以解析各种风格的命令行,但是通常这些命令行都有固定的写法,这个写法一般还记不住要找一个模板参考以下。cobra除了可以解析命令行之外,还提供了命令行,可以生成模板。先安装这个命令行, 并且把库的依赖加到go.mod里
1 | $ go get -u github.com/spf13/cobra/cobra
|
登录后复制
cobra会安装到$GOPATHbin
目录下,注意环境变量中把它加入PATH中
1 2 3 | $ cobra init --pkg-name github.com/shalk/blog -a shalk -l mit
Your Cobra applicaton is ready at
D:\code\github.com\shalk\blog
|
登录后复制
目录结构如下:
1 2 3 4 5 6 | ./cmd
./cmd/root.go
./go.mod
./go.sum
./LICENSE
./main.go
|
登录后复制
编译一下
执行一下
1 2 3 4 5 6 7 | $blog -h
A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.
|
登录后复制
命令行就创建好了,看上去一行代码也不用写,由于随着了解的深入,后面需要调整生成的代码,还是要了解一下cobra代码的套路。
cobra代码的套路
有三个概念,command、flag和args ,例如:
这里 get 就是commond(这里比较特殊), -u 就是flag, test.com/a/b 就是args
那么命令行就是有三部分构成,所以需要定义好这个
- 命令自身的一些基本信息,用command表示,具体对象是 cobra.Command
- 命令的一些标致或者选项,用flag表示,具体对象是 flag.FlagSet
- 最后的参数,用args表示,通常是[]string
还有一个概念是子命令,比如get就是go的子命令,这是一个树状结构的关系。
我可以使用go命令,也可以使用 go get命令
例如: root.go,定义了root命令,另外在init里面 定义了flag,如果它本身有具体执行,就填充Run字段。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | var rootCmd = &cobra.Command{
Use: "blog" ,
Short: "A brief description of your application" ,
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os. Exit (1)
}
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config" , "" , "config file (default is $HOME/.blog.yaml)" )
rootCmd.Flags().BoolP( "toggle" , "t" , false, "Help message for toggle" )
}
|
登录后复制
如果需要子命令,就需要在init 里,给 rootCmd.AddCommand() 其他的command,其他的子命令通常也会单独用一个文件编写,并且有一个全局变量,让rootCmd可以add它
创建子命令
1 2 3 4 5 6 7 8 9 10 11 | D:\code\github.com\shalk\blog>cobra add new
new created at D:\code\github.com\shalk\blog
D:\code\github.com\shalk\blog>cobra add delete
delete created at D:\code\github.com\shalk\blog
D:\code\github.com\shalk\blog>cobra add list
list created at D:\code\github.com\shalk\blog
D:\code\github.com\shalk\blog>cobra add edit
edit created at D:\code\github.com\shalk\blog
|
登录后复制
cmd 目录下增加了 new.go, delete.go,list.go,edit.go
增加功能代码
new.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | var newCmd = &cobra.Command{
Use: "new" ,
Short: "create new post" ,
Long: `create new post `,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New( "requires a color argument" )
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
fileName := "posts/" + args[0]
err := os. Mkdir ( "posts" , 644)
if err != nil {
log.Fatal(err)
}
_, err = os.Stat( fileName)
if os.IsNotExist(err) {
file, err := os.Create(fileName)
if err != nil {
log.Fatal(err)
}
log.Printf( "create file %s" , fileName)
defer file.Close()
} else {
}
},
}
|
登录后复制
list.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var listCmd = &cobra.Command{
Use: "list" ,
Short: "list all blog in posts" ,
Long: `list all blog in posts `,
Run: func(cmd *cobra.Command, args []string) {
_, err := os.Stat( "posts" )
if os.IsNotExist(err) {
log.Fatal( "posts dir is not exits" )
}
dirs, err := ioutil.ReadDir( "posts" )
if err != nil {
log.Fatal( "read posts dir fail" )
}
fmt.Println( "------------------" )
for _, dir := range dirs {
fmt.Printf( " %s\n" , dir.Name() )
}
fmt.Println( "------------------" )
fmt.Printf( "total: %d blog\n" , len(dirs))
},
}
|
登录后复制
delete.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | var deleteCmd = &cobra.Command{
Use: "delete" ,
Short: "delete a post" ,
Long: ` delete a post`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return errors.New( "requires a color argument" )
}
if strings.Contains(args[0], "/" ) || strings.Contains(args[0], ".." ) {
return errors.New( "posts name should not contain / or .. " )
}
return nil
},
Run: func(cmd *cobra.Command, args []string) {
fileName := "./posts/" + args[0]
stat, err := os.Stat(fileName)
if os.IsNotExist(err) {
log.Fatalf( "post %s is not exist" , fileName)
}
if stat.IsDir() {
log.Fatalf( "%s is dir ,can not be deleted" , fileName)
}
err = os.Remove(fileName)
if err != nil {
log.Fatalf( "delete %s fail, err %v" , fileName, err)
} else {
log.Printf( "delete post %s success" , fileName)
}
},
}
|
登录后复制
edit.go 这个有一点麻烦,因为如果调用一个程序比如vim 打开文件,并且golang程序本身要退出,需要detach。暂时放一下(TODO)
编译测试
我是window测试,linux 更简单一点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | PS D:\code\github.com\shalk\blog> go build -o blog.exe .
PS D:\code\github.com\shalk\blog> .\blog.exe list
------------------
------------------
total: 0 blog
PS D:\code\github.com\shalk\blog> .\blog.exe new blog1.md
2020/07/26 22:37:15 create file posts/blog1.md
PS D:\code\github.com\shalk\blog> .\blog.exe new blog2.md
2020/07/26 22:37:18 create file posts/blog2.md
PS D:\code\github.com\shalk\blog> .\blog.exe new blog3.md
2020/07/26 22:37:20 create file posts/blog3.md
PS D:\code\github.com\shalk\blog> .\blog list
------------------
blog1.md
blog2.md
blog3.md
------------------
total: 3 blog
PS D:\code\github.com\shalk\blog> .\blog delete blog1.md
2020/07/26 22:37:37 delete post ./posts/blog1.md success
PS D:\code\github.com\shalk\blog> .\blog list
------------------
blog2.md
blog3.md
------------------
total: 2 blog
PS D:\code\github.com\shalk\blog> ls .\posts\
目录: D:\code\github.com\shalk\blog\posts
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2020/7/26 22:37 0 blog2.md
-a---- 2020/7/26 22:37 0 blog3.md
PS D:\code\github.com\shalk\blog>
|
登录后复制
小结
cobra 是一个高效的命令行解析库,利用cobra的脚手架,可以快速的实现一个命令行工具。如果需要更细致的控制,可以参考cobra的官方文档。
以上是一个golang常见库cobra的详细内容。更多信息请关注PHP中文网其他相关文章!