Explanation of Flags in Go - go

Can anyone explain flags in Go?
flag.Parse()
var omitNewline = flag.Bool("n", false, "don't print final newline")

flags are a common way to specify options for command-line programs.
package main
import (
"flag"
"fmt"
)
var (
env *string
port *int
)
// Basic flag declarations are available for string, integer, and boolean options.
func init() {
env = flag.String("env", "development", "a string")
port = flag.Int("port", 3000, "an int")
}
func main() {
// Once all flags are declared, call flag.Parse() to execute the command-line parsing.
flag.Parse()
// Here we’ll just dump out the parsed options and any trailing positional
// arguments. Note that we need to dereference the points with e.g. *evn to
// get the actual option values.
fmt.Println("env:", *env)
fmt.Println("port:", *port)
}
Run Programs:
go run main.go
Try out the run program by first giving it without flags. Note that if you omit flags they automatically take their default values.
go run command-line-flags.go --env production --port 2000
If you provide a flag with specified value then default will overwrite by passed one.

See http://golang.org/pkg/flag/ for a full description.
The arguments for flag.Bool are (name string, value bool, usage string)
name is the argument to look for, value is the default value and
usage describes the flag's purpose for a -help argument or similar, and is displayed with flag.Usage().
For more detailed example check here

flag is used to parse command line arguments. If you pass "-n" as a command line argument, omitNewLine will be set to true. It's explained a bit farther in the tutorial :
Having imported the flag package, line 12 creates a global variable to hold the value of echo's -n flag. The variable omitNewline has type *bool, pointer to bool.

Personally, I prefer the Var type functions, as they take a reference, rather
than returning a reference. That way you can use the variable without
dereferencing:
package main
import "flag"
func main() {
var omitNewline bool
flag.BoolVar(&omitNewline, "n", false, "don't print final newline")
flag.Parse()
println(omitNewline)
}
https://golang.org/pkg/flag#BoolVar

Related

Require a flag as the first argument in a Cobra command

I'm trying to create a Cobra command that uses a flag to inform the action of the command, specifically a configuration command that can either add or remove a configured setting. For example
cli> prog_name config --set config_var var_vlue
cli> prog_name config --unset config_var var_value
Is there a way to do this in Cobra? I have been reading through the documentation and haven't found any way to validate that a flag is the first value in the command. I've seen information about positional arguments, but from what I've read it sounds like flags aren't considered arguments, so they wouldn't be covered by positional arguments.
I'd imagine I can do this in my PreRunE function and do the validation manually, but if there's a way to set this in Cobra I think that'd most likely be better, since I'd prefer Cobra to be doing that parsing and matching rather than me have to be comparing specific values in os.Args to "--set" and "--unset" or something similar.
It seems like the best option is to just use a subcommand for this instead of a flag.
You can solve this by consulting this link.
In short what you need is the Flags() function. You can find documentation here.
package main
import (
"fmt"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "testprog",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("rootCmd called")
},
}
var subCmd = &cobra.Command{
Use: "sub",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(args)
},
}
func main() {
rootCmd.AddCommand(subCmd)
flags := subCmd.Flags()
// not necessary in your case
flags.SetInterspersed(false)
// Bool defines a bool flag with specified name,
// default value, and usage string. The return value
// is the address of a bool variable that stores
// the value of the flag.
flags.Bool("test", false, "test flag")
rootCmd.Execute()
}
Let's see what happens in the terminal:
> ./cobraApp sub --test a
> [a]

How do I iterate through command line arguments and collect what's left over after the flags?

My goal is for "init", "init -site=test", both versions of init and also the standalone "debug" command to be accepted at the command line, and to treat anything left over as a filename.
What actually happens is that in the case of "init -site=test" for some reason the "-site=test" is also accepted as a filename. How can I stop that from happening?
package main
import (
"flag"
"fmt"
"os"
)
func main() {
initCmd := flag.NewFlagSet("init", flag.ExitOnError)
initSiteName := initCmd.String("site", "", "Main name for your site")
flag.Parse()
for pos, cmd := range os.Args {
switch cmd {
case "debug":
fmt.Printf("debug\n")
case "init":
initCmd.Parse(os.Args[pos+1:])
fmt.Printf("init\n site name:%v\n", *initSiteName)
default:
fmt.Printf("Filename: %v\n", cmd);
}
}
}
It's not very convenient using the flag package. From the doc:
Flag parsing stops just before the first non-flag argument ("-" is a non-flag argument) or after the terminator "--".
You would have to do it manually:
After parsing, the arguments following the flags are available as the slice flag.Args() or individually as flag.Arg(i).
Or you can use another package.

Why can't I pass a pointer to fmt.Println using flag.StringVar?

I've started looking at Golang, and following an example to pass in command line arguments, I've got this code:
package main
import (
"flag"
"fmt"
)
func main() {
wordPtr := flag.String("namestring", "stringvalue", "Pass in a string")
numPtr := flag.Int("number", 11, "Pass in an int")
boolPtr := flag.Bool("switchflag", false, "Pass in a bool")
var svar string
flag.StringVar(&svar, "svar", "svarstringvalue", "A string variable")
flag.Parse()
fmt.Println("Word:", *wordPtr)
fmt.Println("Word2:", wordPtr)
fmt.Println("numb:", *numPtr)
fmt.Println("numb2", numPtr)
fmt.Println("switchflag", *boolPtr)
fmt.Println("switchflag2", boolPtr)
fmt.Println("svar:", svar)
fmt.Println("svar2", &svar)
fmt.Println("svar3", *svar) //<-- This won't work...
fmt.Println("tail:", flag.Args())
}
My question is, why do I get the value of the other pointers if I dereference it (like *wordPtr etc), whereas if I pass wordPtr in, I get the memory address, but with svar, I have to pass in svar to get the value, and &svar gets me the memory address?
Looking at the documentation here https://golang.org/pkg/flag/, it says that you pass in a variable to store the flag (presumably a variable that is already created?), but I still don't understand why I have to do something different to it to get the value, when compared with other variables.
This is the result of me running it with passing in some commands:
➜ Documents go run main.go -number 42 -switchflag -svar testtringvalue
Word: stringvalue
Word2: 0xc42005c1e0
numb: 42
numb2 0xc4200160a0
switchflag true
switchflag2 0xc4200160a8
svar: testtringvalue
svar2 0xc42005c1f0
tail: []
Any help is appreciated. Also, if I've got any understanding of it wrong, please let me know.
Cheers.
Well this is fairly simple, you are trying to dereference a value instead of pointer.
var svar string is not a pointer, but a value.
fmt.Println("svar3", svar) is correct use in this case
Don't worry about about use of StringVar as
...Var(&svar, "sv... means that you are passing address of svar not a value.

How to enter an optional flag with no parameters in Go CLI program

I have read the docs for the following two libraries used to create flags. :
https://golang.org/pkg/flag/
https://github.com/codegangsta/cli
And have not come across a way to do optional flags. How can this be done?
According to the code from https://gobyexample.com/command-line-flags :
package main
import "flag"
import "fmt"
func main() {
boolPtr := flag.Bool("fork", false, "a bool")
fmt.Println("fork:", *boolPtr)
}
and executed by :
$ ./command-line-flags -fork
Should result in true, this is the behavior I desire but I am getting false on my machine.
Any guidance would be appreciated,
Thanks
You must parse the flags after all flags are defined and before flags are accessed:
func main() {
boolPtr := flag.Bool("fork", false, "a bool")
flag.Parse() // add this line
fmt.Println("fork:", *boolPtr)
}
With this change, the fork flag will work as desire.

Golang derefencing function return value

I'm messing with the flag library, and found that this code does not work:
package main
import (
"fmt"
"flag"
)
var recursive bool
func init() {
recursive = *flag.Bool("r", false, "Search recursively")
}
func main() {
flag.Parse()
fmt.Printf("Recursive: %t \n\n", recursive)
flag.PrintDefaults()
}
But this does (I commented the three lines I changed):
package main
import (
"fmt"
"flag"
)
var recursive *bool //Changed to pointer type
func init() {
recursive = flag.Bool("r", false, "Search recursively") //Changed to not dereference function
}
func main() {
flag.Parse()
fmt.Printf("Recursive: %t \n\n", *recursive) //Changed to dereference variable
flag.PrintDefaults()
}
Why does this behave like this? Are functions not allowed to be dereferenced in Golang, or am I doing something else wrong?
The reason for this is because when you call flag.Bool(), it does not yet parse the command line arguments, it just defines a named flag and initializes it with the default value (which is false as you specified it).
Command line arguments are only parsed when you call flag.Parse(). If you use recursive bool, in the init() function the default false will be assigned to it. The flag package does not know about your recursive variable, so later when you call flag.Parse(), its value will not/ cannot be changed.
flag.Bool() returns a pointer to a bool variable which the flag package knows about, and later when you call flag.Parse() the pointed bool variable will be properly updated, so when you print the pointed valued after flag.Bool(), it will be the updated value which will be set based on your command line arguments.
Alternative: Register your variable
So you must store and use the pointer returned by flag.Bool() else you will only see the default value. Or you can let the flag package know about your recursive variable: you can tell the flag package that you what it to store the result into your recursive variable by telling this with the flag.BoolVar() function:
flag.BoolVar(&recursive, "r", false, "Search recursively")
Note that in this case there is no return value, becase you explicitly provided a pointer to a bool which you want the flag package to store the result to.

Resources