2017-05-08 12:32



the docs in cobra and viper are confusing me. I did cobra init fooproject and then inside the project dir I did cobra add bar. I have a PersistentFlag that is named foo and here is the init function from the root command.

func Execute() {
    if err := RootCmd.Execute(); err != nil {

    fmt.Println("fooString is: ", fooString)

func init() {

    // Here you will define your flags and configuration settings.
    // Cobra supports Persistent Flags, which, if defined here,
    // will be global for your application.

    RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.fooproject.yaml)")
    RootCmd.PersistentFlags().StringVar(&fooString, "foo", "", "loaded from config")

    viper.BindPFlag("foo", RootCmd.PersistentFlags().Lookup("foo"))
    // Cobra also supports local flags, which will only run
    // when this action is called directly.
    RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")

my config file looks like this...

foo: aFooString

and when I call go run main.go I see this...

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.

  fooproject [command]

Available Commands:
  bar         A brief description of your command
  help        Help about any command

      --config string   config file (default is $HOME/.fooproject.yaml)
      --foo string      loaded from config
  -h, --help            help for fooproject
  -t, --toggle          Help message for toggle

Use "fooproject [command] --help" for more information about a command.

fooString is:

When I call go run main.go bar I see this...

Using config file: my/gopath/github.com/user/fooproject/.fooproject.yaml
bar called

fooString is:

so it is using the config file but neither one of them seems to be reading it, maybe I am misunderstanding the way that cobra and viper work, any ideas?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答


  • dtnpf35197 dtnpf35197 4年前

    To combine spf13/cobra and spf13/viper,

    first define the flag with cobra:

    RootCmd.PersistentFlags().StringP("foo", "", "loaded from config")

    bind it with viper:

    viper.BindPFlag("foo", RootCmd.PersistentFlags().Lookup("foo"))

    and get the variable via the viper's method:

    fmt.Println("fooString is: ", viper.GetString("foo"))
    点赞 评论 复制链接分享
  • dongque8332 dongque8332 3年前

    Since Viper values are somewhat inferior to pflags (e.g. no support for custom data types), I was not satisfied with answer "use Viper to retrieve values", and ended up writing small helper type to put values back in pflags.

    type viperPFlagBinding struct {
            configName string
            flagValue  pflag.Value
    type viperPFlagHelper struct {
            bindings []viperPFlagBinding
    func (vch *viperPFlagHelper) BindPFlag(configName string, flag *pflag.Flag) (err error) {
            err = viper.BindPFlag(configName, flag)
            if err == nil {
                    vch.bindings = append(vch.bindings, viperPFlagBinding{configName, flag.Value})
    func (vch *viperPFlagHelper) setPFlagsFromViper() {
            for _, v := range vch.bindings {
    func main() {
            var rootCmd = &cobra.Command{}
            var viperPFlagHelper viperPFlagHelper
            rootCmd.PersistentFlags().StringVar(&config.Password, "password", "", "API server password (remote HTTPS mode only)")
            viperPFlagHelper.BindPFlag("password", rootCmd.Flag("password"))
            rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
                    err := viper.ReadInConfig()
                    if err != nil {
                            if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
                                    return err
                    return nil
    点赞 评论 复制链接分享