Can you specify optional arguments to a flag in Cobra?

1.7k Views Asked by At

Let's say I have this flag in my program that only prints a positive number:

c.PersistentFlags().IntVar(&SomeFlag, optionSomeFlag, 0, "do something (range: x-y)")

The default is 0 so if the user doesn't toggle the flag, nothing is printed. How can I make the flag accept arguments but have a default itself? i.e. if the default was 5

./program --someflag output would be 5

but if I did

./program --someflag=1 output would be 1

I tried following the user guide for Cobra and was expecting a command type that would allow me to specify default values only if the user triggers the flag, not just altogether. I may have misinterpreted this or missed something though.

2

There are 2 best solutions below

0
On BEST ANSWER

It can be done using NoOptDefVal

rootCmd.PersistentFlags().Lookup("someflag").NoOptDefVal = "5"

In the following code, you can find a complete example of a command line application with cobra that have the behavior you describe

package main

import (
    "fmt"
    "github.com/spf13/cobra"
)

func main() {
    var someFlag int
    var defaultSomeFlag = "5"

    // Create the root command.
    rootCmd := &cobra.Command{
        Use:   "program",
        Short: "A brief description of your application",
        Long:  "A longer description of your application",
        Run: func(cmd *cobra.Command, args []string) {
            // Check whether the flag was explicitly set.
            if cmd.Flags().Lookup("someflag").Changed {
                fmt.Printf("someflag: %d\n", someFlag)
            } else {
                // If the flag was not explicitly set don't print a value.
                fmt.Printf("someflag is not set\n")
            }
        },
    }

    // Define the flag and set its default value.
    rootCmd.PersistentFlags().IntVar(&someFlag, "someflag", 0, "do something (range: x-y)")
    rootCmd.PersistentFlags().Lookup("someflag").NoOptDefVal = defaultSomeFlag

    // Execute the root command.
    if err := rootCmd.Execute(); err != nil {
        fmt.Println(err)
    }
}

Below are the results of the execution with different flag values.

$ ./test
someflag is not set
$ ./test --someflag
someflag: 5
$ ./test --someflag=3
someflag: 3
0
On

I was planning to work around this limitation by parsing os.Args[1:] myself to look for the flag without a parameter and insert the default value into a modified copy of the arguments and pass the modified copy to rootCommand.SetArgs.

It feels a bit hackish and hard to sustain but I don't see another solution.