golang常用库:cli命令行/应用程序生成工具-cobra使用

一、Cobra 介绍

我前面有一篇文章介绍了配置文件解析库 Viper 的使用,这篇介绍 Cobra 的使用,你猜的没错,这 2 个库都是同一个作者 spf13,他开发了很多与 golang 相关的库,他目前在 google 领导着 golang 产品相关开发工作。

Cobra 是关于 golang 的一个命令行解析库,用它能够快速创建功能强大的 cli 应用程序和命令行工具。

它被很多知名的项目使用,比如 KubernetesGithub CLIEtcd 等。更多应用此库的项目列表

我们平常用到命令:git commit -m "message",docker containter start 等都可以用 cobra 来实现。

Cobra 相关文档地址:

Cobra 的logo:

(from:https://github.com/spf13/cobra)

二、功能特性介绍

  • 很多子命令的CLIS: 比如 app server、app fetch 等
  • 支持嵌套子命令(sub-command)
  • 轻松完成应用程序和命令的创建:cobra init appname 和 cobra add cmdname
  • 为应用程序生成 man 手册
  • 全局、本地和级联 flag
  • 为 shell 程序完成自动提示(bash,zsh,fish, powershell etc.)
  • 支持命令行别名,可以帮助你更容易更改内容而不破坏他们
  • 灵活定义自己的help、usage信息
  • 可选集成 viper 配置管理工具库

更多功能特性请查看: cobra文档介绍

三、Cobra cli 命令结构说明

Cobra 命令结构由3部分组成:

commands、arguments 和 flags

  • commands:

    命令行,代表行为动作,要执行的一个动作。每个命令还可以包含子命令。分为:rootCmd 和 subCmd。程序中具体对象是 cobra.Command{},这个是根命令;子命令(subCmd)用 rootCmd.AddCommand() 添加,子命令通常也会单独存一个文件,

    并通过一个全局变量让 rootCmd 可以 add 它。

  • arguments:

    命令行参数,通常是 []string 表示

  • flags:

    命令行选项。对 command 进一步的控制。通常用一短横 - 或者两短横 -- 标识。程序中读取存储在变量中。

cobra 命令行格式:

  1. APPNAME VERB NOUN --ADJECTIVE
  2. APPNEM COMMAND ARG --FLAG

例子说明:

  1. hugo server --port=1313 #server 代表 command, port 代表 flag。
  2. git clone URL --bare #clone 代表 command,URL 代表操作的物-argument,bare 代表 flag。

四、Cobra 基本使用方法

golang v1.15, cobra v1.2.1

安装 cobra:

  1. go get -u github.com/spf13/cobra

可以用 cobra -h 来查看 cobra 命令的一些用法。

  1. Usage:
  2. cobra [command]
  3. Available Commands:
  4. add Add a command to a Cobra Application
  5. completion generate the autocompletion script for the specified shell
  6. help Help about any command
  7. init Initialize a Cobra Application

init 命令初始化应用程序

安装 cobra generator:go get -u github.com/spf13/cobra/cobra

使用命令 cobra init 来创建第一个应用程序,这个命令也是初始化一个应用程序的项目框架:

  1. cobra init firstappname
  2. Error: required flag(s) "pkg-name" not set

报错了,错误信息截图如下:

错误信息:需要设置 --pkg-name 参数。

因为我们项目不存在。先创建名为 firstappname 文件夹,然后进入目录 firstappname,在命令行下运行:cobra init --pkg-name firstappname

自动生成了如下目录和程序:

下面程序我去掉了英文注释部分。

main.go

  1. package main
  2. import "firstappname/cmd"
  3. func main() {
  4. cmd.Execute()
  5. }

cmd/root.go

  1. package cmd
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/spf13/cobra"
  6. "github.com/spf13/viper"
  7. )
  8. var cfgFile string
  9. // 构建根 command 命令。前面我们介绍它还可以有子命令,这个command里没有构建子命令
  10. var rootCmd = &cobra.Command{
  11. Use: "firstappname",
  12. Short: "A brief description of your application",
  13. Long: `A longer description that spans multiple lines and likely contains
  14. examples and usage of using your application. For example:
  15. Cobra is a CLI library for Go that empowers applications.
  16. This application is a tool to generate the needed files
  17. to quickly create a Cobra application.`
  18. }
  19. // 执行 rootCmd 命令并检测错误
  20. func Execute() {
  21. cobra.CheckErr(rootCmd.Execute())
  22. }
  23. func init() {
  24. // 加载运行初始化配置
  25. cobra.OnInitialize(initConfig)
  26. // rootCmd,命令行下读取配置文件,持久化的 flag,全局的配置文件
  27. rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.firstappname.yaml)")
  28. // local flag,本地化的配置
  29. rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
  30. }
  31. // 初始化配置的一些设置
  32. func initConfig() {
  33. if cfgFile != "" {
  34. viper.SetConfigFile(cfgFile) // viper 设置配置文件
  35. } else {// 上面没有指定配置文件,下面就读取 home 下的 .firstappname.yaml文件
  36. // 配置文件参数设置
  37. home, err := os.UserHomeDir()
  38. cobra.CheckErr(err)
  39. viper.AddConfigPath(home)
  40. viper.SetConfigType("yaml")
  41. viper.SetConfigName(".firstappname")
  42. }
  43. viper.AutomaticEnv()
  44. if err := viper.ReadInConfig(); err == nil {// 读取配置文件
  45. fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
  46. }
  47. }

其实上面的错误在 cobra generator 文档里有提示了,所以要多看官方文档。

这个 root.go 里的 cobra.Command 就是设置命令行格式的地方。如果要执行相关的命令,可以在 Long:...下面加一行:

  1. Run: func(cmd *cobra.Command, args []string) { },

运行程序:go run main.go , 报错了:

我用的是 go v1.15,GO111MODULE="on"。

用 go mod 来创建 module,进入firstappname目录,命令: go mod init firstappname ,生成一个 go.mod,

  1. module firstappname
  2. go 1.15
  3. require (
  4. github.com/spf13/cobra v1.2.1
  5. github.com/spf13/viper v1.9.0
  6. )

在运行 go run main.go,第一次运行会下载文件到 go.mod, go.sum 里。再次运行,就会出现 rootCmd 下的 Long 信息。

  1. A longer description that spans multiple lines and likely contains
  2. examples and usage of using your application. For example:
  3. Cobra is a CLI library for Go that empowers applications.
  4. This application is a tool to generate the needed files
  5. to quickly create a Cobra application.

可以看出,用 cobra init 命令初始化的项目, 生成了一个初始化的应用框架,但是没有任何逻辑功能。仅仅输出一些描述性信息。

这个程序里,最重要的是 cmd/root.go 里的 rootCmd = &cobra.Command{} 这行程序,这里定义命令动作。

程序里的 init() 和 initConfig() 函数都是对命令行的配置。

为 rootCmd 添加功能:

  1. var rootCmd = &cobra.Command{
  2. Use: "firstappname",
  3. Short: "A brief description of your application",
  4. Long: `(root)A longer description that spans multiple lines and likely contains
  5. examples and usage of using your application. For example:
  6. Cobra is a CLI library for Go that empowers applications.
  7. This application is a tool to generate the needed files
  8. to quickly create a Cobra application.`,
  9. Run: func(cmd *cobra.Command, args []string) {
  10. fmt.Println("root called")
  11. },
  12. }

测试运行 go run main.go ,输出:

  1. $ go run main.go
  2. root called

运行:go run main.go --help

会输出上面的 Long 信息和完整的帮助信息。

也可以把上面命令编译:go build -o demo.exe,在运行

完整生成一个cobra应用框架的命令:

  1. $ mkdir firstappname
  2. $ cd firstappname
  3. $ cobra init --pkg-name firstappname
  4. $ go mod init firstappname

add 生成子命令subCmd

上面我们用 cobra init 创建了应用程序框架,在程序 cmd/root.go 里有一个根命令 rootCmd,也就是说 init 命令创建了一个根命令。执行 command 命令是 &cobra.Command{} 里的 Run 方法。

cobra add 来为 rootCmd 创建一个子命令。这个子命令通常在一个单独的文件里。

  1. 用 add 命令生成子命令代码:
  1. // cd 进入firstappname
  2. $ cd ./firstappname
  3. $ cobra add demo
  4. demo created at D:\work\mygo\common_pkg\cobra\firstappname

在 cmd 目录下生成了 demo.go 文件:

  1. 为子命令添加简单功能

    add 命令已经为我们生成了一个简单的应用代码,程序文件通常存放在cmd目录下,demo.go 程序:

    1. package cmd
    2. import (
    3. "fmt"
    4. "github.com/spf13/cobra"
    5. )
    6. // demoCmd represents the demo command
    7. // 子命令
    8. var demoCmd = &cobra.Command{
    9. Use: "demo",
    10. Short: "A brief description of your command",
    11. Long: `A longer description that spans multiple lines and likely contains examples
    12. and usage of using your command. For example:
    13. Cobra is a CLI library for Go that empowers applications.
    14. This application is a tool to generate the needed files
    15. to quickly create a Cobra application.`,
    16. Run: func(cmd *cobra.Command, args []string) {
    17. fmt.Println("demo called")
    18. fmt.Println("cmd demo")
    19. },
    20. }
    21. func init() {
    22. rootCmd.AddCommand(demoCmd)
    23. }

到现在为止,为 firstappdemo 添加了 2 个 Command 了,分别是根命令 rootCmd 和子命令 demoCmd。

子命令和根命令的关系一般通过程序 rootCmd.AddCommand() 方法确定。在程序 demo.go 里可以看到它在 init() 函数里。

Run 方法里添加程序:fmt.Println("cmd demo")。一般这里的程序都是其他 package 里完成了具体逻辑,然后 Run 方法里在调用这些程序。

测试运行:go run main.go demo

输出:

demo called

cmd demo

也可以编译项目 go build -o xxx 在运行。

Flags使用-给Command添加flags

flag 命令行选项,也叫标识,对command命令行为的进一步指示操作。

用这个标识可以给 command 添加一些可选项。

根据 flag 选项作用范围不同,可以分为 2 类:

  • Persistent Flags,持久化的flag,全局范围

    如果设置全局范围的flag,可以用这个来设置。它既可以给根命令设置选项值,也可以给子命令设置选项值。

    下面例子里的 rootCmd 和 demoCmd 都可以调用 flag。

  • Local Flags,局部flag,只对指定的command生效。比如某个子命令的 flag。

因为 flag 标识是在命令行后面不同位置使用,所以我们要在方法外定义一个变量,来分配存储使用这个标识符。下面例子会说明。

Persistent Flags 全局flag例子

  1. 在 cmd/root.go 文件中添加一个变量 name

    1. var cfgFile string
    2. // 添加 name
    3. var name string

    然后在 root.go:init() 函数中添加全局 persistent flag,把 flag 值存储到变量 name 中

    1. rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.firstappname.yaml)")
    2. // 添加全局 flag
    3. rootCmd.PersistentFlags().StringVar(&name, "name", "", "Set one name")
  2. 在文件 cmd/demo.go 中的 demoCmd(子命令) 里 Run 方法输出 name 值

    1. Run: func(cmd *cobra.Command, args []string) {
    2. fmt.Println("demo called")
    3. fmt.Println("cmd demo")
    4. // 打印输出 name
    5. fmt.Println("print persistent flag name: ", name)
    6. },
  3. 测试运行程序

    1. $ go run main.go demo --name setname
    2. demo called
    3. cmd demo
    4. print persistent flag name: setname

    当然也可以先编译 go build -o cobrademo.exe(我用的win),然后在运行测试程序

    1. $.\cobrademo.exe demo --name setname1
    2. demo called
    3. cmd demo
    4. print persistent flag name: setname1

Persistent flag 的读取方法:

  1. // arg1:存储变量,
  2. // arg2:设置长flag名,这里 name 显示 --name,
  3. // arg3:设置短flag名,这里 n 显示 -n,一般与上面对应
  4. // arg4:默认值, 这里设置为 ""
  5. // arg5:flag的一些说明信息
  6. PersistentFlags().StringVarP(&name, "name", "n", "", "Set one name")
  7. // 与上面用法基本相同,只是没有短 flag 设置
  8. PersistentFlags().StringVar(&name, "name", "", "Set one name")
  9. // 直接设置flag名,arg1:flag 名,arg2:默认值,arg3:说明
  10. PersistentFlags().String("foo", "", "A help for foo")

Local Flags例子

一个 flag 赋值给本地变量,只能对指定的command生效。

我们在 demo.go 中测试 local flag。

  1. 在 cmd/demo.go 文件中定义变量 dsn,存储这个 flag 值
  1. // 定义 local flag
  2. var dsn string
  1. 在 demo.go 中的 init() 中添加下面代码,把值存储到 dsn上

    1. demoCmd.Flags().StringVarP(&dsn, "dsn", "d", "", "dsn file")
  2. 在 demoCmd.Command{} 获取该值

    1. Run: func(cmd *cobra.Command, args []string) {
    2. fmt.Println("demo called")
    3. fmt.Println("cmd demo")
    4. // 打印输出 name
    5. fmt.Println("print persistent flag name: ", name)
    6. // 打印输出local flag: dsn
    7. fmt.Println("(local flag)print dsn: ", dsn)
    8. },
  3. 测试运行

    1. $ go run .\main.go demo --dsn setdsn1
    2. demo called
    3. cmd demo
    4. print persistent flag name:
    5. (local flag)print dsn: setdsn1

    输出了 setdsn1。

测试下其它子命令可以不可以获取这个 dsn,添加一个新的子命令 demo2,

  1. $ cobra add demo2

在目录 cmd 下添加了文件 demo2.go, 在 Run 下添加:

  1. Run: func(cmd *cobra.Command, args []string) {
  2. fmt.Println("demo2 called")
  3. // 添加输出 dsn
  4. fmt.Println("test get local flag(dsn): ", dsn)
  5. },

测试:

  1. $ go run .\main.go demo2 --dsn testdsn
  2. Error: unknown flag: --dsn

报错了,程序终止运行了。

说明:local flag 局部选项,只能作用于指定的 command。本例子中作用于 demoCmd,而不能作用于 demo2Cmd。

local flag 的读取方法:

  1. // arg1:存储变量,
  2. // arg2:设置长flag名,这里 name 显示 --name,
  3. // arg3:设置短flag名,这里 n 显示 -n,一般与上面对应
  4. // arg4:默认值, 这里设置为 ""
  5. // arg5:flag的一些说明信息
  6. // 方法(1)
  7. Flags().StringVarP(&name, "name", "n", "", "Set one name")
  8. // 与上面方法(1)用法基本相同,只是没有短 flag 设置
  9. Flags().StringVar(&name, "name", "", "Set one name")
  10. // 直接设置flag名,arg1:flag 名,arg2:默认值,arg3:说明
  11. Flags().String("foo", "", "A help for foo")
  12. // 与上面方法(1)用法基本相同,除了第一个没有变量读取参数
  13. Flags().StringP("toggle", "t", false, "Help message for toggle")

完整例子在 github 上,golang-library-learning/cobra

设置flag必填项

比如给 demo.go 的 dsn 这个 flag 设置必选项

  1. demoCmd.Flags().StringVarP(&dsn, "dsn", "d", "", "dsn file")
  2. // 把 dsn 设置为必选项
  3. demoCmd.MarkFlagRequired("dsn")

flag 不设置dsn,运行程序:go run main.go demo, 报错:Error: required flag(s) "dsn" not set

  1. $ go run .\main.go demo
  2. Error: required flag(s) "dsn" not set
  3. Usage:
  4. firstappname demo [flags]
  5. Flags:
  6. -d, --dsn string dsn file
  7. -h, --help help for demo
  8. Global Flags:
  9. --config string config file (default is $HOME/.firstappname.yaml)
  10. --name string Set one name
  11. Error: required flag(s) "dsn" not set
  12. exit status 1

加上 dsn 运行,go run main.go demo --dsn setdsn,正常输出:

  1. $ go run main.go demo --dsn setdsn
  2. demo called
  3. cmd demo
  4. print persistent flag name:
  5. (local flag)print dsn: setdsn

绑定配置

还可以绑定配置到 flags 上,用 viper

在 cmd/root.go 里,有一个 initConfig() 方法,这个就是初始化配置方法。加载执行是在 init() 方法里,

  1. func init() {
  2. cobra.OnInitialize(initConfig)
  3. ... ...
  4. }

我们可以在 init() 方法中添加绑定 flag 程序,

  1. rootCmd.PersistentFlags().StringVar(&name, "name", "", "Set one name")
  2. viper.BindPFlag("name", rootCmd.PersistentFlags().Lookup("name"))

这样就将 viper 配置和 flag 绑定,如果用户不设置 --name,将从配置中查找。

更多方法请查看 viper flag doc

arguments 命令行参数设置

可以用Command 的 Args 字段指定参数效验规则。

Cobra 也内置了一些规则:

  • NoArgs:如果有任何命令行args参数,将会报错

  • ArbitraryArgs:该命令接受任何参数

  • OnlyValidArgs:如果该命令参数不在 Command 的 ValidArgs 中,将会报错

  • MinimumArgs(int): 如果命令参数数目少于N个,将会报错

  • MaximumArgs(int): 如果命令参数数目多于N个,将会报错

  • ExactArgs(int): 如果命令参数数目不是N个,将会报错

  • RangeArgs(min, max):如果命令参数数目范围不在(min, max),将会报错

内置效验规则的例子:

  1. var rootCmd = &cobra.Command{
  2. Use: "dmeo",
  3. Short: "demo short",
  4. Long: `let's do it, demo!`,
  5. Args: cobra.MinimumNArgs(5),
  6. Run: func(cmd *cobra.Command, args []string) {
  7. fmt.Println("hello chenqionghe")
  8. },
  9. }

自定义验证规则的例子:

  1. var cmd = &cobra.Command {
  2. Short: "demo",
  3. Args: func(cmd *cobra.Command, args[] string) error {
  4. if len(args) > 0 {
  5. return errors.New("requires a color argument")
  6. }
  7. if myapp.IsValidColor(args[0]) {
  8. return nil
  9. }
  10. return fmt.Errorf("invalid color specified: %s", args[0])
  11. },
  12. Run: func(cmd *cobra.Command, args []string) {
  13. fmt.Println("Hello, demo!")
  14. },
  15. }

钩子函数 PreRun and PostRun Hooks

可以在执行命令之前或之后运行钩子函数。如果子命令未声明自己的 Persistent * Run 函数,则子命令将继承父命令的钩子函数。

函数的执行顺序为:

  • PersistentPreRun
  • PreRun
  • Run
  • PostRun
  • PersistentPostRun
  1. package main
  2. import (
  3. "fmt"
  4. "github.com/spf13/cobra"
  5. )
  6. func main() {
  7. var rootCmd = &cobra.Command{
  8. Use: "root [sub]",
  9. Short: "My root command",
  10. PersistentPreRun: func(cmd *cobra.Command, args []string) {
  11. fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args)
  12. },
  13. PreRun: func(cmd *cobra.Command, args []string) {
  14. fmt.Printf("Inside rootCmd PreRun with args: %v\n", args)
  15. },
  16. Run: func(cmd *cobra.Command, args []string) {
  17. fmt.Printf("Inside rootCmd Run with args: %v\n", args)
  18. },
  19. PostRun: func(cmd *cobra.Command, args []string) {
  20. fmt.Printf("Inside rootCmd PostRun with args: %v\n", args)
  21. },
  22. PersistentPostRun: func(cmd *cobra.Command, args []string) {
  23. fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args)
  24. },
  25. }
  26. subCmd := &cobra.Command{
  27. Use: "sub [no options!]",
  28. Short: "My subcommand",
  29. PreRun: func(cmd *cobra.Command, args []string) {
  30. fmt.Printf("Inside subCmd PreRun with args: %v\n", args)
  31. },
  32. Run: func(cmd *cobra.Command, args []string) {
  33. fmt.Printf("Inside subCmd Run with args: %v\n", args)
  34. },
  35. PostRun: func(cmd *cobra.Command, args []string) {
  36. fmt.Printf("Inside subCmd PostRun with args: %v\n", args)
  37. },
  38. PersistentPostRun: func(cmd *cobra.Command, args []string) {
  39. fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args)
  40. },
  41. }
  42. rootCmd.AddCommand(subCmd)
  43. rootCmd.SetArgs([]string{""})
  44. rootCmd.Execute()
  45. fmt.Println()
  46. rootCmd.SetArgs([]string{"sub", "arg1", "arg2"})
  47. rootCmd.Execute()
  48. }

运行程序:

  1. $ go run .\hookdemo.go
  2. Inside rootCmd PersistentPreRun with args: []
  3. Inside rootCmd PreRun with args: []
  4. Inside rootCmd Run with args: []
  5. Inside rootCmd PostRun with args: []
  6. Inside rootCmd PersistentPostRun with args: []
  7. Inside rootCmd PersistentPreRun with args: [arg1 arg2] // 子命令继承了父命令的函数
  8. Inside subCmd PreRun with args: [arg1 arg2]
  9. Inside subCmd Run with args: [arg1 arg2]
  10. Inside subCmd PostRun with args: [arg1 arg2]
  11. Inside subCmd PersistentPostRun with args: [arg1 arg2]

为你的命令生成文档

Cobra 可以基于子命令、标志等生成文档。具体的使用方法和生产格式文档请点击下面链接:

你可以设置 cmd.DisableAutoGenTag = true 从而把文档中 "Auto generated by spf13/cobra..." 等字样删掉。

help 命令

命令: cobra help,可以清楚显示出对使用 cobra 有用的信息,比如命令提示

你还可以定义自己的 help 命令或模板

  1. cmd.SetHelpCommand(cmd *Command)
  2. cmd.setHelpCommand(f func(*Command, []string))
  3. cmd.setHelpTemplate(s string)

五、参考

cobra github

cobra user guide

Cobra Generator

golang常用库:cli命令行/应用程序生成工具-cobra使用的更多相关文章

  1. PHP的CLI命令行运行模式浅析

    在做开发的时候,我们不仅仅只是做各种网站或者接口,也经常需要写一些命令行脚本用来处理一些后端的事务.比如对数据进行处理统计等.当然也是为了效率着想,当一个事务有可能会有较长的耗时时,往往会交由服务器的 ...

  2. 测试常用的Oracle11G 命令行指令。

    测试常用的Oracle11G 命令行指令. ×××××××××××××××× 登录:

  3. ThinkPHP3.1.2 使用cli命令行模式运行

    ThinkPHP3.1.2 使用cli命令行模式运行 标签(空格分隔): php 前言 thinkphp3.1.2 需要使用cli方法运行脚本 折腾了一天才搞定 3.1.2的版本真的很古老 解决 增加 ...

  4. python pip使用国内镜像安装第三方库:命令行或PyCharm

    python pip使用国内镜像安装第三方库:命令行或PyCharm 转载: https://blog.csdn.net/lly1122334/article/details/80646996

  5. APICloud提供适用于命令行的开发工具,开发更具极客精神!

    APICloud近期大动作不断,上周刚刚支持Atom编辑器,并推出核心开发工具库.本周又为开发者提供了一款超轻便的新开发工具--CLI工具! 操作系统: Mac/Windows/Linux nodej ...

  6. Linux系统——28个命令行下的工具

    Unix/Linux下的28个命令行下的工具 下面是Kristóf Kovács收集的28个Unix/Linux下的28个命令行下的工具(原文链接),有一些是大家熟悉的,有一些是非常有用的,有一些是不 ...

  7. 命令行视频下载工具 you-get 和 youtube-dl

    you-get 和 youtube-dl 都是基于 Python 的命令行媒体文件下载工具,完全开源免费跨平台.用户只需使用简单命令并提供在线视频的网页地址即可让程序自动进行嗅探.下载.合并.命名和清 ...

  8. PHP 命令行参数解析工具类

    <?php/** * 命令行参数解析工具类 * @author guolinchao * @email luoyecb@163.com */class CommandLine{ // store ...

  9. VMware10中的CentOS6.5命令行安装VMwaretools工具启用windows与虚拟机中Linux系统的共享目录

    VMware10中的CentOS6.5命令行安装VMwaretools工具启用windows与虚拟机中Linux系统的共享目录 一.描述 系统描述:win7旗舰版64位系统+VMware Workst ...

随机推荐

  1. C# 获取动态类中所有的字段

    /// <summary>        /// 动态类 获取字典集合        /// </summary>        /// <typeparam name= ...

  2. ECShop 文章添加缩略图功能

    为 ECShop 文章添加缩略图     ECShop 文章不包含缩略图比较遗憾,不过它的文章里包含一个附件上传,而且一般不会用到,这样,我们就可以改动一下,让它成为缩略图. 首先在 includes ...

  3. 【Azure 应用服务】App Service For Linux 部署PHP Laravel 项目,如何修改首页路径为 wwwroot\public\index.php

    问题描述 参考官方文档部署 PHP Laravel 项目到App Service for Linux环境中,但是访问应用时候遇见了500 Server Error 错误. 从部署的日志中,可以明确看出 ...

  4. Shell系列(28)- 条件判断之字符串判断

    字符串判断 $变量时要用双引号引起来,即"$变量" 测试选项 作用 -z 字符串 判断字符串是否为空(为空返回真) -n 字符串 判断字符串是否为非空(非空返回真) 字符串1 == ...

  5. Appium WebView控件定位

    背景 移动应用可以粗分为三种:原生应用(native app), 网页应用(web app,或HTML5 app),以及它们的混血儿--混合模式移动应用(hybrid app). 什么是Hybrid ...

  6. 常用的jquery 中一些js

    目录: 1.验证用户登录信息 2. 获取下拉框所选中的元素 3.  动态获取 id 和对应文本框的值  4. table 中 tr  的隐藏 5 . 更换图片  6. ajax  进行提交 7. 判断 ...

  7. node.js及npm安装&配置

    之前我们在文言文安装教程里写过node.js及npm的安装,这里我们详细写一下. 下载node.js node.js下载分为两种,官网nodejs.org,和国内官网nodejs.cn,国内的童鞋建议 ...

  8. mysql-router-MIC-8.0.26集群部署

    1.具体部署详情请看视频 https://space.bilibili.com/677825194 2.mysql主要配置如下 cat > /etc/my.cnf <<EOF [cl ...

  9. 分片利器 AutoTable:为用户带来「管家式」分片配置体验

    在<DistSQL:像数据库一样使用 Apache ShardingSphere>一文中,Committer 孟浩然为大家介绍了 DistSQL 的设计初衷和语法体系,并通过实战操作展示了 ...

  10. HAOI2012高速公路bzoj2752 (线段树,数学)

    题目大意: 给定一个长度为n的链,一共m次操作 对于每次操作 \(C\ l\ r\ x\)表示将第l个点到第r个点之间的所有道路的权值增加v \(Q\ l\ r\)在第l个到第r个点里等概率随机取出两 ...